排序规则功能允许按列甚至按操作指定数据的排序顺序和字符分类行为。这消除了数据库创建后无法更改 LC_COLLATE
和 LC_CTYPE
设置的限制。
概念上,每个可排序数据类型的表达式都有一个排序规则。(内置的可排序数据类型是 text
、varchar
和 char
。用户定义的基类型也可以标记为可排序,当然,覆盖可排序数据类型的 域也是可排序的。)如果表达式是列引用,则表达式的排序规则是该列定义的排序规则。如果表达式是常量,则排序规则是该常量数据类型的默认排序规则。更复杂表达式的排序规则将根据下面描述的其输入的排序规则派生而来。
表达式的排序规则可以是“默认”排序规则,这意味着为数据库定义的区域设置。表达式的排序规则也可能是不确定的。在这种情况下,排序操作和其他需要了解排序规则的操作将失败。
当数据库系统需要执行排序或字符分类时,它将使用输入表达式的排序规则。例如,这发生在 ORDER BY
子句以及函数或操作符调用(如 <
)时。ORDER BY
子句要应用的排序规则就是排序键的排序规则。要应用于函数或操作符调用的排序规则将根据下面描述的参数派生而来。除了比较操作符之外,排序规则还会被转换为大小写字母的函数(如 lower
、upper
和 initcap
)、模式匹配操作符以及 to_char
和相关函数考虑在内。
对于函数或操作符调用,通过检查参数排序规则派生的排序规则将在运行时用于执行指定的操作。如果函数或操作符调用的结果是可排序数据类型,则该排序规则还将在解析时用作函数或操作符表达式的定义排序规则,以防存在需要了解其排序规则的包含表达式。
表达式的“排序规则推导”可以是隐式的或显式的。这个区别影响了当表达式中出现多个不同的排序规则时,它们是如何组合的。当使用 COLLATE
子句时,会发生显式排序规则推导;所有其他排序规则推导都是隐式的。当需要组合多个排序规则时(例如在函数调用中),将使用以下规则:
如果任何输入表达式具有显式排序规则推导,则输入表达式中的所有显式推导的排序规则必须相同,否则将引发错误。如果存在任何显式推导的排序规则,则它就是排序规则组合的结果。
否则,所有输入表达式必须具有相同的隐式排序规则推导或默认排序规则。如果存在任何非默认排序规则,则它就是排序规则组合的结果。否则,结果就是默认排序规则。
如果输入表达式之间存在冲突的非默认隐式排序规则,则该组合被视为具有不确定的排序规则。除非被调用的特定函数需要知道它应该应用的排序规则,否则这不是一个错误条件。如果是这样,将在运行时引发错误。
例如,考虑以下表定义
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;
解析器无法确定应用哪个排序规则,因为 a
和 b
列具有冲突的隐式排序规则。由于 <
操作符确实需要知道使用哪个排序规则,这将导致错误。通过为任一输入表达式附加显式排序规则说明符,可以解决此错误,例如:
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";
排序规则是一个 SQL schema 对象,它将 SQL 名称映射到操作系统中安装的库提供的区域设置。排序规则定义有一个“提供者”,它指定哪个库提供区域设置数据。一个标准的提供者名称是 libc
,它使用操作系统 C 库提供的区域设置。这些是操作系统提供的大多数工具使用的区域设置。另一个提供者是 icu
,它使用外部 ICU 库。只有在构建 PostgreSQL 时配置了 ICU 支持,才能使用 ICU 区域设置。
由 libc
提供的排序规则对象映射到 LC_COLLATE
和 LC_CTYPE
设置的组合,这些设置被 setlocale()
系统库调用接受。(正如名称所示,排序规则的主要目的是设置 LC_COLLATE
,它控制排序顺序。但在实践中,很少需要 LC_CTYPE
设置与 LC_COLLATE
不同,因此将其收集到一个概念下比创建另一个为每个表达式设置 LC_CTYPE
的基础设施更方便。)此外,libc
排序规则与字符集编码相关联(参见 第 23.3 节)。相同的排序规则名称可能存在于不同的编码中。
由 icu
提供的排序规则对象映射到 ICU 库提供的命名排序器。ICU 不支持单独的“排序”和“类型”设置,因此它们总是相同的。此外,ICU 排序规则独立于编码,因此在数据库中给定名称的 ICU 排序规则始终只有一个。
在所有平台上,都支持以下排序规则:
unicode
此 SQL 标准排序规则使用 Unicode 排序算法和默认 Unicode 排序元素表进行排序。它在所有编码中都可用。使用此排序规则需要 ICU 支持,并且如果 PostgreSQL 使用不同版本的 ICU 构建,其行为可能会发生变化。(此排序规则与 ICU 根区域设置的行为相同;参见 und-x-icu
(表示“未定义”)。)
ucs_basic
此 SQL 标准排序规则使用 Unicode 代码点值而不是自然语言顺序进行排序,并且只有 ASCII 字母“A
”到“Z
”被视为字母。其行为高效且在所有版本中都稳定。仅适用于 UTF8
编码。(此排序规则与 UTF8
编码中的 libc 区域设置规范 C
具有相同的行为。)
pg_unicode_fast
此排序规则通过 Unicode 代码点值而不是自然语言顺序进行排序。对于 lower
、initcap
和 upper
函数,它使用 Unicode 完全大小写映射。对于模式匹配(包括正则表达式),它使用 Unicode 兼容属性的标准变体。行为在 Postgres 的主要版本内是高效且稳定的。仅适用于 UTF8
编码。
pg_c_utf8
此排序规则通过 Unicode 代码点值而不是自然语言顺序进行排序。对于 lower
、initcap
和 upper
函数,它使用 Unicode 简单大小写映射。对于模式匹配(包括正则表达式),它使用 Unicode 兼容属性的 POSIX 兼容变体。行为在 PostgreSQL 的主要版本内是高效且稳定的。此排序规则仅适用于 UTF8
编码。
C
(等同于 POSIX
)C 和 POSIX 排序规则基于“传统 C”行为。它们按字节值而不是自然语言顺序排序,并且只有 ASCII 字母“A
”到“Z
”被视为字母。对于给定的数据库编码,其行为在所有版本中都是高效且稳定的,但不同数据库编码之间的行为可能有所不同。
default
default 排序规则选择数据库创建时指定的区域设置。
根据操作系统支持,可能还有其他排序规则可用。这些附加排序规则的效率和稳定性取决于排序规则提供者、提供者版本和区域设置。
如果操作系统支持在单个程序中使用多个区域设置(newlocale
及相关函数),或者如果配置了 ICU 支持,那么当数据库集群初始化时,initdb
会根据它在初始化时在操作系统中找到的所有区域设置,使用排序规则填充系统目录 pg_collation
。
要检查当前可用的区域设置,请使用查询 SELECT * FROM pg_collation
,或在 psql 中使用命令 \dOS+
。
例如,操作系统可能提供名为 de_DE.utf8
的区域设置。initdb
将为 UTF8
编码创建一个名为 de_DE.utf8
的排序规则,该排序规则将 LC_COLLATE
和 LC_CTYPE
都设置为 de_DE.utf8
。它还将创建一个名称后缀为 .utf8 的排序规则。因此,您也可以使用 de_DE
这个名称使用排序规则,这样写起来更方便,并且名称对编码的依赖性更小。请注意,尽管如此,初始的排序规则名称集是平台依赖的。
libc
提供的默认排序规则集直接映射到操作系统中安装的区域设置,可以使用命令 locale -a
列出。如果需要一个 LC_COLLATE
和 LC_CTYPE
值不同的 libc
排序规则,或者在数据库系统初始化后在操作系统中安装了新的区域设置,则可以使用 CREATE COLLATION 命令创建新的排序规则。也可以使用 pg_import_system_collations()
函数批量导入新的操作系统区域设置。
在任何特定的数据库中,只有使用该数据库编码的排序规则才是有意义的。pg_collation
中的其他条目将被忽略。因此,即使“de_DE
”这样的剥离名称在全局不唯一,在给定数据库中也可以认为它是唯一的。建议使用剥离名称的排序规则,因为如果您决定更改数据库编码,需要更改的内容会少一项。但请注意,default
、C
和 POSIX
排序规则可以不考虑数据库编码而使用。
PostgreSQL 认为不同的排序规则对象即使具有相同的属性也是不兼容的。因此,例如:
SELECT a COLLATE "C" < b COLLATE "POSIX" FROM test1;
将引发错误,即使 C
和 POSIX
排序规则具有相同的行为。因此,不建议混合使用剥离的和非剥离的排序规则名称。
使用 ICU 时,枚举所有可能的区域设置名称是不合理的。ICU 使用一种特殊的区域设置命名系统,但命名的区域设置方式比实际存在的不同区域设置要多得多。initdb
使用 ICU API 来提取一组不同的区域设置,以填充排序规则的初始集合。ICU 提供的排序规则在 SQL 环境中创建,名称采用 BCP 47 语言标签格式,并附加了“私有使用”扩展 -x-icu
,以区别于 libc 排序规则。
以下是一些可能创建的示例排序规则:
某些(较少使用的)编码不受 ICU 支持。当数据库编码是其中之一时,pg_collation
中的 ICU 排序规则条目将被忽略。尝试使用它们将导致类似于“排序规则“de-x-icu”对于编码“WIN874”不存在”的错误。
如果标准和预定义排序规则不满足需求,用户可以使用 SQL 命令 CREATE COLLATION 创建自己的排序规则对象。
与所有预定义对象一样,标准和预定义排序规则位于 pg_catalog
schema 中。用户定义的排序规则应在用户 schema 中创建。这也能确保它们被 pg_dump
保存。
可以像这样创建新的 libc 排序规则:
CREATE COLLATION german (provider = libc, locale = 'de_DE');
此命令中 locale
子句可接受的确切值取决于操作系统。在类 Unix 系统上,命令 locale -a
将显示列表。
由于预定义的 libc 排序规则已经包含了数据库实例初始化时在操作系统中定义的所有排序规则,因此很少需要手动创建新的排序规则。可能的原因是如果需要不同的命名系统(在这种情况下,请参见 第 23.2.2.3.3 节),或者操作系统已升级以提供新的区域设置定义(在这种情况下,请参见 pg_import_system_collations()
)。
可以像这样创建 ICU 排序规则:
CREATE COLLATION german (provider = icu, locale = 'de-DE');
ICU 区域设置指定为 BCP 47 语言标签,但也可以接受大多数 libc 风格的区域设置名称。如果可能,libc 风格的区域设置名称将被转换为语言标签。
通过在语言标签中包含排序规则设置,新的 ICU 排序规则可以广泛地定制排序规则行为。有关详细信息和示例,请参阅 第 23.2.3 节。
命令 CREATE COLLATION 也可用于从现有排序规则创建新的排序规则,这有助于在应用程序中使用与操作系统无关的排序规则名称,创建兼容名称,或者使用 ICU 提供的排序规则作为更易读的名称。例如:
CREATE COLLATION german FROM "de_DE"; CREATE COLLATION french FROM "fr-x-icu";
排序规则可以是“确定性”或“非确定性”的。确定性排序规则使用确定性比较,这意味着它仅当字符串由相同的字节序列组成时才认为它们相等。非确定性比较可能会确定字符串相等,即使它们由不同的字节组成。典型情况包括不区分大小写、不区分重音符号以及比较不同 Unicode 规范形式的字符串。由排序规则提供者实际实现这种不区分大小写的比较;确定性标志仅决定是否使用字节序比较来打破平局。有关术语的更多信息,请参阅 Unicode 技术标准 10。
要创建非确定性排序规则,请在 CREATE COLLATION
中指定属性 deterministic = false
,例如:
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 规范形式的文本,也可以选择使用 normalize
和 is normalized
函数/表达式来预处理或检查字符串,而不是使用非确定性排序规则。每种方法都有不同的权衡。
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 节。
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 |
在每个级别,即使完全不进行规范化,也会执行基本规范化。例如,'á'
可能由代码点 U&'\0061\0301'
或单个代码点 U&'\00E1'
组成,即使在 identic
级别,这些序列也被视为相等。要将代码点表示的任何差异视为不同,请使用 deterministic
设置为 true
创建的排序规则。
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 显示了可用的排序规则设置,这些设置可以用作语言标签的一部分来定制排序规则。
表 23.2. ICU 排序规则设置
键 | 值 | 默认 | 描述 |
---|---|---|---|
co |
emoji 、phonebk 、standard 、... |
standard |
排序规则类型。有关其他选项和详细信息,请参阅 第 23.2.3.5 节。 |
ka |
noignore 、shifted |
noignore |
如果设置为 shifted ,则某些字符(例如标点符号或空格)在比较时将被忽略。键 ks 必须设置为 level3 或更低才能生效。设置键 kv 来控制哪些字符类别将被忽略。 |
kb |
true 、false |
false |
级别 2 差异的反向比较。例如,区域设置 und-u-kb 将 'àe' 排序在 'aé' 之前。 |
kc |
true 、false |
false |
将大小写分隔为“级别 2.5”,介于重音符号和其他级别 3 特征之间。 如果设置为 |
kf |
upper 、lower 、false |
false |
如果设置为 upper ,则大写字母排在小写字母之前。如果设置为 lower ,则小写字母排在大写字母之前。如果设置为 false ,则排序取决于区域设置的规则。 |
kn |
true 、false |
false |
如果设置为 true ,则字符串中的数字被视为单个数值而不是数字序列。例如,'id-45' 排在 'id-123' 之前。 |
kk |
true 、false |
false |
启用完全规范化;可能会影响性能。即使设置为 在某些情况下,例如当多个重音符号应用于单个字符时,完全规范化很重要。例如,代码点序列 |
kr |
space 、punct 、symbol 、currency 、digit 、script-id |
设置为一个或多个有效值,或任何 BCP 47 重新定义字符类的顺序;列表中较早的类中的字符在列表较晚的类中的字符之前排序。例如,值 |
|
ks |
level1 、level2 、level3 、level4 、identic |
level3 |
确定相等性时的敏感性(或“强度”),level1 对差异的敏感性最低,identic 对差异的敏感性最高。有关详细信息,请参阅 表 23.1。 |
kv |
space 、punct 、symbol 、currency |
punct |
级别 3 比较时被忽略的字符类别。设置为较晚的值时包括较早的值;例如 symbol 也包括 punct 和 space 在要忽略的字符中。键 ka 必须设置为 shifted 并且键 ks 必须设置为 level3 或更低才能生效。 |
默认值可能取决于区域设置。上表并非旨在详尽无遗。有关其他选项和详细信息,请参阅 第 23.2.3.5 节。
对于许多排序规则设置,必须将排序规则创建为 deterministic
设置为 false
才能使该设置产生预期效果(参见 第 23.2.2.4 节)。此外,某些设置只有在键 ka
设置为 shifted
时才生效(参见 表 23.2)。
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
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');
#结合了以上两个选项。
如果上述排序规则设置提供的选项不足,可以使用定制规则更改排序元素顺序,其语法在 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 节)仅是对 ICU 行为和语言标签的简要概述。有关技术细节、其他选项和新行为,请参阅以下文档:
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。