排序规则功能允许为每列甚至每个操作指定分类行为和数据排序顺序。这样就可以避免在创建后无法更改数据库的 LC_COLLATE
和 LC_CTYPE
设置这一限制。
概念上,可整理数据类型的所有表达式均有整理规则。(内置的可整理数据类型包括 text
、varchar
和 char
。用户定义的基本类型也可以标记为可整理,当然对于可整理数据类型之上 域 也可整理。)如果表达式是列引用,那么该表达式的整理规则就是列的已定义整理规则。如果表达式是常量,那么整理规则就是常量数据类型的默认整理规则。更复杂表达式的整理规则将从其输入整理规则派生,如下所述。
表达式的整理规则可以是 “default” 整理规则,表示数据库定义的区域设置。表达式的整理规则也可能未确定。在这种情况下,需要了解整理规则的排序操作和其他操作将失败。
当数据库系统必须执行排序或字符分类时,它将使用输入表达式的整理规则。例如,这将发生在 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 架构对象,它将 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 不支持单独的“整理”和“ctype”设置,因此它们总是一样的。此外,ICU 整理与编码无关,因此数据库中指定名称的 ICU 整理总是只有一个。
在所有平台上,均支持以下排序规则
unicode
使用 Unicode 整理算法和默认 Unicode 整理元素表对这种 SQL 标准排序规则进行整理。它适用于所有编码。使用此排序规则需要 ICU 支持,如果使用不同版本的 ICU 构建 Postgres,行为可能会改变。(此排序规则具有与 ICU 根区域设置相同的行为;请参见und-x-icu
(对于“undefined”)。)
ucs_basic
此 SQL 标准排序使用 Unicode 码点值排序而非自然语言顺序,并且仅将 ASCII 字母 “A
” 到 “Z
” 视为字母。行为在所有版本之间都是高效且稳定的。仅可用于编码 UTF8
。(此排序与 UTF8
编码中的 libc 区域设置规范 C
具有相同的行为。)
pg_c_utf8
此排序按 Unicode 码点值而不是自然语言顺序排序。对于函数 lower
、initcap
和 upper
,它使用 Unicode 简单大小写映射。对于模式匹配(包括正则表达式),它使用 Unicode 兼容性属性 的 POSIX 兼容变体。行为在 Postgres 主要版本内是高效且稳定的。此排序仅可用于编码 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
列出。如果需要 libc
对照,且其 LC_COLLATE
和 LC_CTYPE
的值不同,或者在数据库系统初始化后在操作系统中安装了新的区域设置,那么可以使用 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 整理规则条目。尝试使用一项时,会引发错误,如“"编码为 "WIN874" 的整理规则 "de-x-icu" 不存在"。
如果标准和预定义的整理规则不够用,用户可以使用 SQL 命令 CREATE COLLATION 创建自己的整理规则对象。
标准和预定义的整理规则在模式 pg_catalog
中,与所有预定义对象一样。应在用户模式中创建用户定义的整理规则。这也确保它们由 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 排列级别
在每个级别上,即使在完全规范化关闭的情况下,也会执行基本规范化。例如,'á'
可由代码点 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 |
假 |
第 2 级差异的反向比较。例如,区域设置 und-u-kb 将 'àe' 排在 'aé' 之前。 |
kc |
true 、false |
假 |
将大写和小写分隔到介于重音和其他第 3 级特征之间的“第 2.5 级”。 如果设置为 |
kf |
upper 、lower 、false |
假 |
如果设置为 upper ,大写将排在小写之前。如果设置为 lower ,小写将排在大写之前。如果设置为 false ,排序取决于区域设置的规则。 |
kn |
true 、false |
假 |
如果设置为 true ,字符串中的数字将被视为一个数字值,而不是一系列数字。例如,'id-45' 将排在 'id-123' 之前。 |
kk |
true 、false |
假 |
启用完全规范化;可能影响性能。即使设置为 完全规范在某些情况下很重要,例如,在向单个字符应用多个重音符号时。例如,代码点序列 |
kr |
space (空格)、punct (标点符号)、symbol (符号)、currency (货币)、digit (数字)、script-id (脚本 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 中定义的 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');
#组合以上两种选项。
如果上面显示的排序规则设置所提供的选项不够用,则可以使用定制规则更改排序元素的顺序,其语法详述在 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 行为和语言标记的一个简要概述。请参阅以下文档,以获取技术详细信息、其他选项和新行为