支持的版本:当前17)/ 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1

23.2. 排序规则支持 #

排序规则特性允许指定每列甚至每个操作的数据的排序顺序和字符分类行为。这减轻了数据库的 LC_COLLATELC_CTYPE 设置在其创建后无法更改的限制。

23.2.1. 概念 #

从概念上讲,可排序数据类型的每个表达式都具有排序规则。(内置的可排序数据类型是 textvarcharchar。用户定义的基类型也可以标记为可排序,当然,在可排序数据类型上的也是可排序的。)如果表达式是列引用,则表达式的排序规则是该列的定义的排序规则。如果表达式是常量,则排序规则是该常量数据类型的默认排序规则。更复杂表达式的排序规则是从其输入的排序规则派生的,如下所述。

表达式的排序规则可以是默认排序规则,这意味着为数据库定义的区域设置。表达式的排序规则也可能是不确定的。在这种情况下,排序操作和其他需要知道排序规则的操作将失败。

当数据库系统必须执行排序或字符分类时,它会使用输入表达式的排序规则。例如,在 ORDER BY 子句以及诸如 < 之类的函数或运算符调用中会发生这种情况。ORDER BY 子句要应用的排序规则只是排序键的排序规则。函数或运算符调用要应用的排序规则是从参数派生的,如下所述。除了比较运算符之外,排序规则还被用于在小写字母和大写字母之间转换的函数,例如 lowerupperinitcap;用于模式匹配运算符;以及用于 to_char 和相关函数。

对于函数或运算符调用,通过检查参数排序规则派生的排序规则在运行时用于执行指定的操作。如果函数或运算符调用的结果是可排序的数据类型,则排序规则也将在解析时用作函数或运算符表达式的定义的排序规则,以防有需要知道其排序规则的周围表达式。

表达式的排序规则派生可以是隐式的或显式的。这种区别会影响当表达式中出现多个不同的排序规则时如何组合排序规则。当使用 COLLATE 子句时,会发生显式排序规则派生;所有其他排序规则派生都是隐式的。当需要组合多个排序规则时,例如在函数调用中,使用以下规则

  1. 如果任何输入表达式具有显式排序规则派生,则输入表达式中所有显式派生的排序规则必须相同,否则会引发错误。如果存在任何显式派生的排序规则,则该排序规则是排序规则组合的结果。

  2. 否则,所有输入表达式必须具有相同的隐式排序规则派生或默认排序规则。如果存在任何非默认排序规则,则该排序规则是排序规则组合的结果。否则,结果是默认排序规则。

  3. 如果输入表达式之间存在冲突的非默认隐式排序规则,则该组合被认为具有不确定的排序规则。除非被调用的特定函数需要知道它应该应用的排序规则,否则这不是错误条件。如果确实需要,则会在运行时引发错误。

例如,考虑以下表定义

CREATE TABLE test1 (
    a text COLLATE "de_DE",
    b text COLLATE "es_ES",
    ...
);

然后在

SELECT a < 'foo' FROM test1;

根据 de_DE 规则执行 < 比较,因为该表达式将隐式派生的排序规则与默认排序规则组合在一起。但是在

SELECT a < ('foo' COLLATE "fr_FR") FROM test1;

比较使用 fr_FR 规则执行,因为显式排序规则派生会覆盖隐式排序规则派生。此外,给定

SELECT a < b FROM test1;

解析器无法确定要应用哪个排序规则,因为 ab 列具有冲突的隐式排序规则。由于 < 运算符确实需要知道要使用哪个排序规则,因此会导致错误。可以通过将显式排序规则说明符附加到任一输入表达式来解决该错误,因此

SELECT a < b COLLATE "de_DE" FROM test1;

或者等效地

SELECT a COLLATE "de_DE" < b FROM test1;

另一方面,结构相似的情况

SELECT a || b FROM test1;

不会导致错误,因为 || 运算符不关心排序规则:无论排序规则如何,其结果都相同。

分配给函数或运算符的组合输入表达式的排序规则也被认为适用于函数或运算符的结果,如果该函数或运算符提供可排序数据类型的结果。因此,在

SELECT * FROM test1 ORDER BY a || 'foo';

排序将根据 de_DE 规则完成。但是此查询

SELECT * FROM test1 ORDER BY a || b;

会导致错误,因为即使 || 运算符不需要知道排序规则,ORDER BY 子句也需要。与之前一样,可以通过显式排序规则说明符来解决冲突

SELECT * FROM test1 ORDER BY a || b COLLATE "fr_FR";

23.2.2. 管理排序规则 #

排序规则是一个 SQL 模式对象,它将 SQL 名称映射到操作系统中安装的库提供的区域设置。排序规则定义具有一个提供程序,该提供程序指定哪个库提供区域设置数据。一个标准的提供程序名称是 libc,它使用操作系统 C 库提供的区域设置。这些是操作系统提供的大多数工具使用的区域设置。另一个提供程序是 icu,它使用外部 ICU库。仅当在构建 PostgreSQL 时配置了对 ICU 的支持时,才能使用 ICU 区域设置。

libc 提供的排序规则对象映射到 LC_COLLATELC_CTYPE 设置的组合,如 setlocale() 系统库调用所接受的那样。(顾名思义,排序规则的主要目的是设置 LC_COLLATE,它控制排序顺序。但是,在实践中,很少需要使 LC_CTYPE 设置与 LC_COLLATE 不同,因此将这些收集在一个概念下比创建另一个用于设置每个表达式的 LC_CTYPE 的基础结构更方便。)此外,libc 排序规则与字符集编码相关联(请参阅第 23.3 节)。不同的编码可能存在相同的排序规则名称。

icu 提供的排序规则对象映射到 ICU 库提供的已命名的排序器。ICU 不支持单独的排序ctype设置,因此它们始终相同。此外,ICU 排序规则独立于编码,因此数据库中始终只有一个给定名称的 ICU 排序规则。

23.2.2.1. 标准排序规则 #

在所有平台上,都支持以下排序规则

unicode

此 SQL 标准排序规则使用 Unicode 整理算法和默认 Unicode 整理元素表进行排序。它适用于所有编码。使用此排序规则需要 ICU 支持,如果使用不同版本的 ICU 构建 Postgres,则行为可能会发生变化。(此排序规则的行为与 ICU 根区域设置相同;请参阅und-x-icu(对于未定义。)

ucs_basic

此 SQL 标准排序规则使用 Unicode 代码点值而不是自然语言顺序进行排序,并且只有 ASCII 字母AZ被视为字母。该行为在所有版本中都是高效且稳定的。仅适用于编码 UTF8。(此排序规则的行为与 UTF8 编码中的 libc 区域设置规范 C 相同。)

pg_c_utf8

此排序规则按照 Unicode 代码点值而非自然语言顺序进行排序。对于函数 lowerinitcapupper,它使用 Unicode 简单大小写映射。对于模式匹配(包括正则表达式),它使用 Unicode 兼容属性的 POSIX 兼容变体。在 Postgres 主要版本内,行为高效且稳定。此排序规则仅适用于 UTF8 编码。

C(等同于 POSIX

CPOSIX 排序规则基于 传统 C 行为。它们按字节值而非自然语言顺序进行排序,并且只有 ASCII 字母 AZ 被视为字母。对于给定的数据库编码,行为在所有版本中都高效且稳定,但行为可能因不同的数据库编码而异。

默认

default 排序规则选择在创建数据库时指定的区域设置。

其他排序规则可能可用,具体取决于操作系统支持。这些其他排序规则的效率和稳定性取决于排序规则提供程序、提供程序版本和区域设置。

23.2.2.2. 预定义的排序规则 #

如果操作系统支持在单个程序中使用多个区域设置(newlocale 和相关函数),或者如果配置了对 ICU 的支持,则在初始化数据库集群时,initdb 会使用在当时在操作系统中找到的所有区域设置,填充系统目录 pg_collation 中基于这些区域设置的排序规则。

要检查当前可用的区域设置,请使用查询 SELECT * FROM pg_collation,或者使用 psql 中的命令 \dOS+

23.2.2.2.1. libc 排序规则 #

例如,操作系统可能提供名为 de_DE.utf8 的区域设置。initdb 将为 UTF8 编码创建一个名为 de_DE.utf8 的排序规则,该排序规则的 LC_COLLATELC_CTYPE 都设置为 de_DE.utf8。它还将创建一个排序规则,其名称中去掉了 .utf8 标签。因此,您也可以使用名称 de_DE 下的排序规则,它写起来不太麻烦,并且使名称不太依赖于编码。请注意,尽管如此,排序规则名称的初始集仍然是平台相关的。

libc 提供的默认排序规则集直接映射到操作系统中安装的区域设置,可以使用命令 locale -a 列出。如果需要一个 libc 排序规则,其 LC_COLLATELC_CTYPE 具有不同的值,或者如果在初始化数据库系统后在操作系统中安装了新的区域设置,则可以使用 CREATE COLLATION 命令创建新的排序规则。也可以使用 pg_import_system_collations() 函数批量导入新的操作系统区域设置。

在任何特定的数据库中,只有使用该数据库编码的排序规则才是有意义的。pg_collation 中的其他条目将被忽略。因此,诸如 de_DE 之类的剥离排序规则名称可以在给定数据库中被认为是唯一的,即使它在全局范围内不是唯一的。建议使用剥离的排序规则名称,因为它将减少您在决定更改为其他数据库编码时需要更改的内容。但请注意,defaultCPOSIX 排序规则无论数据库编码如何都可以使用。

PostgreSQL 认为不同的排序规则对象是不兼容的,即使它们具有相同的属性。因此,例如:

SELECT a COLLATE "C" < b COLLATE "POSIX" FROM test1;

即使 CPOSIX 排序规则具有相同的行为,也会引发错误。因此,不建议混合使用剥离和非剥离的排序规则名称。

23.2.2.2.2. ICU 排序规则 #

使用 ICU,枚举所有可能的区域设置名称是不明智的。ICU 对区域设置使用特定的命名系统,但是命名区域设置的方式比实际不同的区域设置要多得多。initdb 使用 ICU API 来提取一组不同的区域设置,以填充排序规则的初始集。ICU 提供的排序规则在 SQL 环境中创建,名称采用 BCP 47 语言标记格式,并附加 私有使用 扩展名 -x-icu,以将它们与 libc 区域设置区分开来。

以下是一些可能创建的排序规则示例

de-x-icu #

德语排序规则,默认变体

de-AT-x-icu #

奥地利的德语排序规则,默认变体

(也有,例如,de-DE-x-icude-CH-x-icu,但截至撰写本文时,它们等效于 de-x-icu。)

und-x-icu(用于未定义 #

ICU 排序规则。使用此规则可获得合理的与语言无关的排序顺序。

ICU 不支持某些(较少使用的)编码。当数据库编码是其中之一时,将忽略 pg_collation 中的 ICU 排序规则条目。尝试使用其中一个会引发类似于 编码“WIN874”的排序规则 "de-x-icu" 不存在 的错误。

23.2.2.3. 创建新的排序规则对象 #

如果标准和预定义的排序规则不足,则用户可以使用 SQL 命令 CREATE COLLATION 创建自己的排序规则对象。

与所有预定义对象一样,标准和预定义的排序规则位于 pg_catalog 模式中。用户定义的排序规则应在用户模式中创建。这也确保了它们会被 pg_dump 保存。

23.2.2.3.1. libc 排序规则 #

可以像这样创建新的 libc 排序规则

CREATE COLLATION german (provider = libc, locale = 'de_DE');

此命令中 locale 子句的可接受确切值取决于操作系统。在类 Unix 系统上,命令 locale -a 将显示一个列表。

由于预定义的 libc 排序规则已经包括在初始化数据库实例时操作系统中定义的所有排序规则,因此通常不需要手动创建新的排序规则。原因可能是如果需要不同的命名系统(在这种情况下,另请参见 第 23.2.2.3.3 节),或者如果操作系统已升级为提供新的区域设置定义(在这种情况下,另请参见 pg_import_system_collations())。

23.2.2.3.2. ICU 排序规则 #

可以像这样创建 ICU 排序规则

CREATE COLLATION german (provider = icu, locale = 'de-DE');

ICU 区域设置指定为 BCP 47 语言标记,但也接受大多数 libc 样式的区域设置名称。如果可能,libc 样式的区域设置名称将转换为语言标记。

新的 ICU 排序规则可以通过在语言标记中包含排序规则属性来广泛自定义排序规则行为。有关详细信息和示例,请参见 第 23.2.3 节

23.2.2.3.3. 复制排序规则 #

命令 CREATE COLLATION 也可用于从现有排序规则创建新的排序规则,这对于能够在应用程序中使用与操作系统无关的排序规则名称、创建兼容性名称或在更易读的名称下使用 ICU 提供的排序规则很有用。例如:

CREATE COLLATION german FROM "de_DE";
CREATE COLLATION french FROM "fr-x-icu";

23.2.2.4. 非确定性排序规则 #

排序规则是 确定性的非确定性的。确定性排序规则使用确定性比较,这意味着它仅当字符串由相同的字节序列组成时才认为它们相等。非确定性比较可能确定字符串即使由不同的字节组成也相等。典型情况包括不区分大小写的比较、不区分重音的比较以及不同 Unicode 规范形式的字符串比较。是否实际实现这种不敏感比较取决于排序规则提供程序;确定性标志仅确定是否使用按字节比较来打破平局。有关术语的更多信息,另请参见 Unicode 技术标准 10

要创建非确定性排序规则,请将属性 deterministic = false 指定给 CREATE COLLATION,例如:

CREATE COLLATION ndcoll (provider = icu, locale = 'und', deterministic = false);

此示例将以非确定性的方式使用标准 Unicode 排序规则。特别是,这将允许正确比较不同规范形式的字符串。更有趣的示例利用了上面解释的 ICU 自定义功能。例如:

CREATE COLLATION case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false);
CREATE COLLATION ignore_accents (provider = icu, locale = 'und-u-ks-level1-kc-true', deterministic = false);

所有标准和预定义的排序规则都是确定性的,默认情况下,所有用户定义的排序规则都是确定性的。虽然非确定性排序规则会给出更 正确 的行为,尤其是在考虑 Unicode 的全部功能及其许多特殊情况时,它们也有一些缺点。最重要的是,它们的使用会导致性能损失。请注意,特别是,B 树不能对使用非确定性排序规则的索引使用重复数据删除。此外,某些操作不能使用非确定性排序规则进行,例如模式匹配操作。因此,应仅在明确需要它们的情况下使用它们。

提示

为了处理不同 Unicode 规范化形式的文本,也可以选择使用函数/表达式 normalizeis normalized 来预处理或检查字符串,而不是使用非确定性排序规则。每种方法都有不同的权衡。

23.2.3. ICU 自定义排序规则 #

ICU 允许通过将排序规则设置定义为语言标记的一部分来广泛控制排序规则行为。这些设置可以修改排序顺序以适应各种需求。例如:

-- ignore differences in accents and case
CREATE COLLATION ignore_accent_case (provider = icu, deterministic = false, locale = 'und-u-ks-level1');
SELECT 'Å' = 'A' COLLATE ignore_accent_case; -- true
SELECT 'z' = 'Z' COLLATE ignore_accent_case; -- true

-- upper case letters sort before lower case.
CREATE COLLATION upper_first (provider = icu, locale = 'und-u-kf-upper');
SELECT 'B' < 'b' COLLATE upper_first; -- true

-- treat digits numerically and ignore punctuation
CREATE COLLATION num_ignore_punct (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-kn');
SELECT 'id-45' < 'id-123' COLLATE num_ignore_punct; -- true
SELECT 'w;x*y-z' = 'wxyz' COLLATE num_ignore_punct; -- true

许多可用的选项在第 23.2.3.2 节中描述,或参阅第 23.2.3.5 节了解更多详细信息。

23.2.3.1. ICU 比较级别 #

ICU 中两个字符串的比较(排序规则)由多级过程确定,其中文本特征被分组到“级别”中。每个级别的处理由排序规则设置控制。级别越高,对应的文本特征越精细。

表 23.1 显示了在给定级别确定相等性时,哪些文本特征差异被认为是重要的。Unicode 字符 U+2063 是一个不可见的 分隔符,如表所示,在所有小于 identic 级别的比较中都会被忽略。

表 23.1. ICU 排序规则级别

级别 描述 'f' = 'f' 'ab' = U&'a\2063b' 'x-y' = 'x_y' 'g' = 'G' 'n' = 'ñ' 'y' = 'z'
level1 基本字符 true true true true true false
level2 重音 true true true true false false
level3 大小写/变体 true true true false false false
level4 标点符号[a] true true false false false false
identic 全部 true false false false false false

[a] 仅在 ka-shifted 时;请参阅表 23.2


在每个级别,即使在完全规范化关闭的情况下,也会执行基本规范化。例如,'á' 可以由代码点 U&'\0061\0301' 或单个代码点 U&'\00E1' 组成,即使在 identic 级别,这些序列也被认为是相等的。要将代码点表示形式的任何差异视为不同,请使用将 deterministic 设置为 true 创建的排序规则。

23.2.3.1.1. 排序规则级别示例 #
CREATE COLLATION level3 (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-level3');
CREATE COLLATION level4 (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-level4');
CREATE COLLATION identic (provider = icu, deterministic = false, locale = 'und-u-ka-shifted-ks-identic');

-- invisible separator ignored at all levels except identic
SELECT 'ab' = U&'a\2063b' COLLATE level4; -- true
SELECT 'ab' = U&'a\2063b' COLLATE identic; -- false

-- punctuation ignored at level3 but not at level 4
SELECT 'x-y' = 'x_y' COLLATE level3; -- true
SELECT 'x-y' = 'x_y' COLLATE level4; -- false

23.2.3.2. ICU 区域设置的排序规则设置 #

表 23.2 显示了可用的排序规则设置,这些设置可以用作语言标签的一部分,以自定义排序规则。

表 23.2. ICU 排序规则设置

默认值 描述
co emojiphonebkstandard... standard 排序规则类型。 有关其他选项和详细信息,请参阅第 23.2.3.5 节
ka noignoreshifted noignore 如果设置为 shifted,则会导致在比较中忽略某些字符(例如标点符号或空格)。 必须将键 ks 设置为 level3 或更低才能生效。设置键 kv 以控制忽略哪些字符类。
kb truefalse false 针对第 2 级差异的反向比较。 例如,区域设置 und-u-kb'àe' 排在 'aé' 之前。
kc truefalse false

将大小写分隔为位于重音和其他第 3 级特征之间的“第 2.5 级”。

如果设置为 true 并且 ks 设置为 level1,则会忽略重音,但会考虑大小写。

kf upperlowerfalse false 如果设置为 upper,则大写字母排在小写字母之前。 如果设置为 lower,则小写字母排在大写字母之前。 如果设置为 false,则排序取决于区域设置的规则。
kn truefalse false 如果设置为 true,则字符串中的数字被视为单个数值,而不是一系列数字。 例如,'id-45' 排在 'id-123' 之前。
kk truefalse false

启用完全规范化;可能会影响性能。 即使设置为 false,也会执行基本规范化。 需要完全规范化的语言的区域设置通常默认启用它。

在某些情况下,完全规范化非常重要,例如当多个重音应用于单个字符时。 例如,代码点序列 U&'\0065\0323\0302'U&'\0065\0302\0323' 表示以不同顺序应用了抑扬符和点下重音的 e。 在完全规范化的情况下,这些代码点序列被视为相等;否则它们是不相等的。

kr spacepunctsymbolcurrencydigitscript-id  

设置为一个或多个有效值,或任何 BCP 47 script-id,例如 latn (“拉丁语”) 或 grek (“希腊语”)。 多个值用“-”分隔。

重新定义字符类的顺序;列表中较早的类的字符排在列表中较晚的类的字符之前。 例如,值 digit-currency-space (作为语言标签(如 und-u-kr-digit-currency-space)的一部分)将标点符号排在数字和空格之前。

ks level1level2level3level4identic level3 确定相等性时的灵敏度(或“强度”),其中 level1 对差异最不敏感,而 identic 对差异最敏感。 有关详细信息,请参阅表 23.1
kv spacepunctsymbolcurrency punct 在第 3 级比较期间忽略的字符类。 设置为较晚的值包括较早的值;例如,symbol 还包括 punctspace 中的要忽略的字符。 必须将键 ka 设置为 shifted,并且必须将键 ks 设置为 level3 或更低才能生效。

默认值可能取决于区域设置。 上表并非完整。 有关其他选项和详细信息,请参阅第 23.2.3.5 节

注意

对于许多排序规则设置,您必须创建将 deterministic 设置为 false 的排序规则,该设置才能具有所需的效果(请参阅第 23.2.2.4 节)。 此外,某些设置仅在将键 ka 设置为 shifted 时才生效(请参阅表 23.2)。

23.2.3.3. 排序规则设置示例 #

CREATE COLLATION "de-u-co-phonebk-x-icu" (provider = icu, locale = 'de-u-co-phonebk'); #

带有电话簿排序规则类型的德语排序规则

CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = 'und-u-co-emoji'); #

根据 Unicode 技术标准 #51,使用 Emoji 排序规则类型的根排序规则

CREATE COLLATION latinlast (provider = icu, locale = 'en-u-kr-grek-latn'); #

将希腊字母排在拉丁字母之前。(默认顺序是拉丁字母排在希腊字母之前。)

CREATE COLLATION upperfirst (provider = icu, locale = 'en-u-kf-upper'); #

将大写字母排在小写字母之前。(默认顺序是小写字母在前。)

CREATE COLLATION special (provider = icu, locale = 'en-u-kf-upper-kr-grek-latn'); #

结合上述两个选项。

23.2.3.4. ICU 定制规则 #

如果上面显示的排序规则设置提供的选项不足,则可以使用定制规则更改排序规则元素的顺序,其语法在 https://unicode-org.github.io/icu/userguide/collation/customization/ 中详细说明。

这个小示例创建一个基于带有定制规则的根区域设置的排序规则

CREATE COLLATION custom (provider = icu, locale = 'und', rules = '&V << w <<< W');

根据此规则,字母 W 排在 V 之后,但被视为与重音类似的次要差异。 此类规则包含在某些语言的区域设置定义中。(当然,如果区域设置定义已经包含所需的规则,则无需再次显式指定。)

这是一个更复杂的示例。 以下语句设置一个名为 ebcdic 的排序规则,其规则按照 EBCDIC 编码的顺序对 US-ASCII 字符进行排序。

CREATE COLLATION ebcdic (provider = icu, locale = 'und',
rules = $$
& ' ' < '.' < '<' < '(' < '+' < \|
< '&' < '!' < '$' < '*' < ')' < ';'
< '-' < '/' < ',' < '%' < '_' < '>' < '?'
< '`' < ':' < '#' < '@' < \' < '=' < '"'
<*a-r < '~' <*s-z < '^' < '[' < ']'
< '{' <*A-I < '}' <*J-R < '\' <*S-Z <*0-9
$$);

SELECT c
FROM (VALUES ('a'), ('b'), ('A'), ('B'), ('1'), ('2'), ('!'), ('^')) AS x(c)
ORDER BY c COLLATE ebcdic;
 c
---
 !
 a
 b
 ^
 A
 B
 1
 2

23.2.3.5. ICU 的外部参考 #

本节(第 23.2.3 节)仅简要概述了 ICU 行为和语言标记。 有关技术细节、其他选项和新行为,请参阅以下文档

提交更正

如果您发现文档中有任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。