PostgreSQL码农集散地

利用DuckDB宏(macro)巧妙发现字符串弱相关

本期播客

利用DuckDB宏(macro)巧妙发现字符串弱相关

这篇duckdb的blog介绍了利用宏(macro)来巧妙查找字符串弱相关的内容.

什么是字符串弱相关?

两个字符串包含相同的字母, 但是这些字母的排序可能是不一样的, 也可能有些字母是重复的. 例如 abc 和 bbacabb .

下面的内容翻译自: https://duckdb.org/2025/09/11/solving-letter-scramble-puzzles.html

请重点关注macro的用法. 如果你熟悉PostgreSQL, 你肯定知道split函数, 以及intarray插件的sort和uniq函数, 把数组排序后去重, 可达到与之类似的效果.

  • https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-POSIX-REGEXP
  • https://www.postgresql.org/docs/current/intarray.html

另外扩展一个小知识, 还有字符串的相似度计算(非语义的相似度), 例如postgresql, p0stgresql, post greSql. 相差了少量字母, 使用PostgreSQL pg_trgm插件可计算其相似度.

  • https://www.postgresql.org/docs/current/pgtrgm.html

使用 DuckDB 解决字母混乱难题

TL;DR:在这篇轻松的文章中,我们解决了荷兰火车上展示的一种谜题类型。

荷兰国家铁路公司 (NS)每周都会发布一款“字母混乱”式的谜题,题目会给出一个词条,其字母可以在荷兰火车站的名称中找到。为了匹配,它不必是完美的字母重排——例如,Amsterdam(9 个字母) 可以匹配mastered(8 个字母) 和Dream Master(11 个字母),因为这三个词条包含相同的字母,只是重复次数不同。我们称之为“弱字母重排”。

九月第一周的谜题是Clumsy Rental Red。让我们尝试使用 DuckDB 来寻找解决方案!

字母规整 macro

首先,让我们创建一个宏,将字符串转换为唯一字符的有序列表:

CREATE MACRO order_letters(s) AS   
    lower(s)                  -- convert all characters to lowercase  
    .regexp_replace(  
'[^\p{L}]', '', 'g'
    )                         -- 正则表达式, remove all non-Unicode letters  
    .string_to_array('')      -- turn the string into a list  
    .list_distinct()          -- eliminate duplicate elements from the list  
    .list_sort();             -- sort the list  

我们可以用它来判断以下字符串1与2、3是否是弱字谜:

SELECT  
    order_letters('Amsterdam') AS letters_1,  
    order_letters('mastered') AS letters_2,  
    order_letters('Dream Master') AS letters_3,  
    letters_1 = letters_2 AS matches_1,  
    letters_1 = letters_3 AS matches_2;  
letters_1
letters_2
letters_3
matches_1
matches_2
[a, d, e, m, r, s, t][a, d, e, m, r, s, t][a, d, e, m, r, s, t]
true
true

事实上,这两个表达都是Amsterdam的弱字谜。

与车站名称匹配

为了解答这个难题,我们需要一个火车站列表。幸运的是,DuckDB 的常用数据集之一是荷兰铁路数据集,其中包括其列车服务和火车站。我们可以创建一个包含车站名称的表:

CREATE TABLE stations AS  
    FROM 'https://blobs.duckdb.org/nl-railway/stations-2023-09.csv';  

然后,我们可以选出谜题中弱字母重排的车站名称:

SELECT name_long  
FROM stations  
WHERE order_letters(name_long) = order_letters('Clumsy Rental Red');  

用于查找弱字母重排的 table 宏

为了找到与字符串弱字母重排的车站名称,我们可以使用table宏:

CREATE MACRO find_weak_anagram(s) AS TABLE  
    SELECT name_long  
    FROM stations  
    WHERE order_letters(name_long) = order_letters(s);  

然后,我们可以使用一个简单的 SQL 语句来找到解决方案:

FROM find_weak_anagram('Clumsy Rental Red');  

弱字谜站对

我们很好奇:有没有两个车站的名字是弱字母重排的?我们可以用这两个车站的名字创建一个笛卡尔积,然后比较它们的字母顺序来找出答案:

SELECT s1.name_long AS station_1, s2.name_long AS station_2  
FROM stations s1, stations s2  
WHERE s1.name_long.order_letters() = s2.name_long.order_letters()  
  -- ensure symmetry-breaking  
  AND s1.name_long < s2.name_long  
  -- make sure the station names don't contain each other  
  AND NOT s1.name_long.contains(s2.name_long)  
  AND NOT s2.name_long.contains(s1.name_long);  

事实上,有三对车站的名称是彼此弱的字母重排:

station_1
station_2
Melsele
Selm
Etten-Leur
Lunteren
Diemen Zuid
Emmen Zuid

清理宏

大多数情况下,运行简单的 DuckDB 脚本后无需清理:只需关闭内存数据库会话即可完成清理。但是,需要指出的是,DuckDB 中的宏是持久化的,这可能会造成一些问题  ——  例如,将数据库复制到DuckLake时:

ATTACH 'ducklake:metadata.ducklake' AS my_ducklake;  
COPY FROM DATABASE memory TO my_ducklake;  

DuckLake 不支持宏(函数),因此会抛出以下错误:

Not implemented Error:  
DuckLake does not support functions

有两种方法可以解决这个问题。

如果您需要保留宏,并且使用 DuckDB 作为 DuckLake 的目录(catalog/元数据)数据库,则可以使用DuckDB 到 DuckLake 的迁移脚本。这会将宏迁移到您的 DuckLake 目录(catalog/元数据)中。

如果您不需要宏或者目标目录数据库不支持它们,则可以使用以下命令删除它们:

DROP MACRO order_letters;  
DROP MACRO TABLE find_weak_anagram;  

没有宏,复制到 DuckLake 调用就会成功。

参考

https://duckdb.org/2025/09/11/solving-letter-scramble-puzzles.html

https://duckdb.org/docs/stable/sql/statements/create_macro.html

https://www.postgresql.org/docs/current/intarray.html

《DuckDB 语法糖macro,columns表达式,list lambda等结合例子: 动态聚合分析》

《DuckDB 宏(MACRO) 的使用》

最后附一则济南的线下峰会消息:
PostgreSQL & IvorySQL 2026 年度峰会将于4月份在济南召开,这是目前国内规模最大的PG峰会. 
我是新特性分论坛出品人,欢迎报名参与分享,主委会可解决分享嘉宾住宿和路费。
报名地址:  https://jsj.top/f/uebqBc

议题方向:

  • PostgreSQL 新功能
  • PostgreSQL 内核机制与性能优化
  • PostgreSQL 扩展程序
  • AI + PostgreSQL 技术实践
  • 云原生PostgreSQL或IvorySQL
  • PostgreSQL 用户实践
  • IvorySQL 兼容性与生态实践
  • 基准测试与性能调优
  • 高可用性技术
  • …… 任何与PostgreSQL或IvorySQL相关的内容