PostgreSQL中实现区分重音的字符串排序及排序规则参数查询问题
PostgreSQL中实现区分重音的字符串排序及排序规则参数查询问题
嗨,我来帮你理清这个问题——你遇到的情况主要是对ICU排序强度级别的逻辑理解有偏差,咱们一步步拆解解决:
一、为什么你的三个自定义排序规则结果一致?
首先得纠正一个认知:你预期的bar < bat < bär其实不是标准的“区分重音排序”,而是字节序排序;而ICU的ks(排序强度级别)的作用逻辑和你想的不太一样:
- level1(primary强度):只比较字符的基字母,完全忽略重音、大小写。理论上
bar和bär会被视为相等,排序顺序是不确定的(因为你设置了deterministic = false) - level2(secondary强度):比较基字母+重音差异,忽略大小写。此时
bar < bär(因为a的重音变体ä的secondary权重高于原字母a),但两者的基字母都是a,优先级远高于bat里的t,所以最终顺序是bar < bär < bat——这其实是完全符合level2区分重音的预期的 - level3(tertiary强度):在level2的基础上再区分大小写,比如
Bar < bar < Bär < bär,但基字母的优先级逻辑和level2一致
如果你确实想得到bar < bat < bär的顺序,那用字节序排序就能实现,PostgreSQL里可以通过COLLATE "C"来触发严格的字节值比较:
SELECT * FROM test ORDER BY string COLLATE "C";
这个查询会直接按每个字符的UTF-8字节值排序,刚好符合你的预期。
二、如何查看内置排序规则的参数细节?
你说得对,pg_collation表确实不会直接显示ICU的ks级别这类参数,但我们有几种方式可以查询到相关信息:
- 查询ICU排序规则的locale参数字符串
对于ICU提供的排序规则(collprovider = 'i'),pg_collation的collcollate字段存储了完整的ICU locale配置字符串,直接查询就能看到所有参数:
SELECT collname, collcollate FROM pg_collation WHERE collprovider = 'i' -- 只查ICU类型的排序规则 AND collname LIKE 'und%'; -- 匹配你创建的und系列排序规则
比如你创建的und2,collcollate会显示und-u-ks-level2,从中就能直接看到它的ks级别是level2。
- 查看系统libc排序规则的参数
对于系统libc提供的排序规则(collprovider = 'c'),需要依赖系统工具查看。比如在Linux上,你可以用locale -k命令查询某个locale的详细配置:
locale -k en_US.UTF-8
命令输出里的collate-weight-table等字段会包含排序权重的细节,但libc的规则不会像ICU那样暴露明确的ks级别,因为两者的参数模型不同。
- 用psql元命令快速查看所有排序规则
在psql客户端中,输入\dAc可以列出所有排序规则的详细信息,包括提供者、locale字符串等,比直接查pg_collation表更直观:
\dAc
补充:如果需要符合语言习惯的区分重音排序
如果你既想区分重音,又希望排序符合特定语言的官方规则(而不是纯字节序),可以放弃通用的und(无语言locale),改用具体语言的ICU locale。比如德语的部分变体中,ä会被视为独立字母排在z之后,你可以尝试:
CREATE COLLATION de_sensitive (provider = icu, deterministic = false, locale = 'de-DE-u-ks-level2'); SELECT * FROM test ORDER BY string COLLATE de_sensitive;
不同语言的locale会有不同的排序逻辑,你可以根据需求选择合适的配置。
内容来源于stack exchange
相关产品推荐
相关产品推荐

