用于 ORDER BY 与相等判断的语言感知比较。

排序规则决定字符串怎么比、怎么排

文本排序是查询契约的一部分。按字节顺序排列的列表,可能不同于按语言习惯排列的列表;忽略大小写的比较,也可能改变唯一约束眼中的“重复名字”。PostgreSQL 不仅有数据库默认规则,还允许在列和表达式上指定排序规则。涉及业务标识、去重或翻页时,应把这些语义写清楚,而不是等不同环境返回不同结果后再猜原因。 坏掉的样子 选了一个语言区域,并不自动意味着不同字节的字符串会相等。确定性排序规则在语言比较相同时,还会使用字节来区分;非确定性规则则允许提供方把不同字节视为等价。对于 ICU,使用 und-u-ks-level2 并设置 deterministic=false,会忽略大小写但仍然区分重音。把这个组合描述为“大小写和重音都不区分”,会直接误导唯一性设计。 比较规则改变后,原先不同的值可能发生碰撞。因此,以新规则创建唯一索引,可能因为已有数据而失败。如果多个名字在新规则下相等,排序还需要明确的第二排序键。翻页时只按不区分大小写的名字排序,不能定义这些等价行之间谁在前谁在后。这里影响的是模式与查询行为,不只是页面上显示哪种字母风格。 快速验证 准备支持 ICU 的 PostgreSQL 18、一个 UTF-8 编码的可丢弃数据库,以及全新的 psql -X -v ON_ERROR_STOP=1 会话。创建排序规则需要对应数据库权限。如果服务器没有 ICU,初始化应明确失败,不要偷偷换成别的区域规则后继续把结果当作同一个实验。先创建忽略大小写的规则,再插入五个名字: CREATE SCHEMA collation_demo; CREATE COLLATION collation_demo.ci (provider=icu,locale='und-u-ks-level2',deterministic=false); CREATE TABLE collation_demo.names (id integer PRIMARY KEY,name text COLLATE "C"); INSERT INTO collation_demo.names VALUES (1,'a'),(2,'A'),(3,'á'),(4,'b'),(5,'B'); SELECT 'a' COLLATE "C" = 'A' AS c_equal, 'a' COLLATE collation_demo.ci = 'A' AS case_equal, 'a' COLLATE collation_demo.ci = 'á' AS accent_equal; 三个比较依次返回假、真、假。字节规则区分大小写;新的语言规则把小写与大写 A 视为相等,但仍区分没有重音和带重音的字母。非确定性开关决定是否使用字节打破比较平局,ICU 的区域与强度决定哪些语言差异会参与比较。删除这个开关,或者改变强度,都已经是在测试另一份契约。 ...

四月 4, 2027 · 2 分钟 · XB Field Notes