## 24.2.排序支持 [24.2.1. 概念](collation.html#id-1.6.11.4.4) [24.2.2. 管理排序规则](collation.html#COLLATION-MANAGING) [](<>) 排序功能允许指定每列甚至每项操作的数据排序顺序和字符分类行为。这减轻了`立法会`和`LC_CTYPE`数据库创建后无法更改其设置。 ### 24.2.1.概念 从概念上讲,可折叠数据类型的每个表达式都有一个排序规则。(内置的可折叠数据类型为`文本`,`瓦尔查尔`和`烧焦`。用户定义的基本类型也可以标记为可折叠,当然,可折叠数据类型上的域是可折叠的。)如果表达式是列引用,则表达式的排序规则是定义的列排序规则。如果表达式是常量,则排序规则是常量数据类型的默认排序规则。更复杂表达式的排序规则是从其输入的排序规则派生出来的,如下所述。 表达式的排序规则可以是“默认”排序规则,这意味着为数据库定义的区域设置。表达式的排序规则也可能是不确定的。在这种情况下,排序操作和其他需要知道排序规则的操作将失败。 当数据库系统必须执行排序或字符分类时,它使用输入表达式的排序规则。例如,这种情况发生在`订购人`子句和函数或运算符调用,例如`<`.申请`订购人`子句只是排序键的排序规则。应用于函数或运算符调用的排序规则来自参数,如下所述。除了比较运算符之外,在小写字母和大写字母之间转换的函数也会考虑排序规则,例如`降低`,`上面的`和`initcap`; 通过模式匹配算子;而且`到_char`以及相关功能。 对于函数或运算符调用,通过检查参数排序规则派生的排序规则在运行时用于执行指定的操作。如果函数或运算符调用的结果是可折叠的数据类型,则在解析时也会使用排序规则作为函数或运算符表达式的已定义排序规则,以防存在需要了解其排序规则的周围表达式。 这个*校勘推导*表达式的形式可以是隐式的,也可以是显式的。当一个表达式中出现多个不同的排序规则时,这种区别会影响排序规则的组合方式。当`整理`使用子句;所有其他排序规则派生都是隐式的。当需要组合多个排序规则时,例如在函数调用中,将使用以下规则: 1. 如果任何输入表达式具有显式排序规则派生,则输入表达式中所有显式派生的排序规则必须相同,否则将引发错误。如果存在任何显式派生的排序规则,则这是排序规则组合的结果。 2. 否则,所有输入表达式必须具有相同的隐式排序规则派生或默认排序规则。如果存在任何非默认排序规则,则这是排序规则组合的结果。否则,结果为默认排序规则。 3. 如果输入表达式之间存在冲突的非默认隐式排序规则,则该组合被视为具有不确定排序规则。这不是错误情况,除非调用的特定函数需要了解它应该应用的排序规则。如果是,则在运行时会引发错误。 例如,考虑这个表定义: ``` CREATE TABLE test1 ( a text COLLATE "de_DE", b text COLLATE "es_ES", ... ); ``` 然后进来 ``` SELECT a < 'foo' FROM test1; ``` 这个`<`比较是根据`德乌德`规则,因为表达式将隐式派生的排序规则与默认排序规则相结合。但是在 ``` 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'; ``` 订购将根据客户要求进行`德乌德`规则。但这个问题: ``` SELECT * FROM test1 ORDER BY a || b; ``` 导致错误,因为即使`||`操作员不需要知道排序规则`订购人`条款确实如此。与之前一样,可以使用显式排序规则说明符解决冲突: ``` SELECT * FROM test1 ORDER BY a || b COLLATE "fr_FR"; ``` ### 24.2.2.管理排序规则 排序规则是一个SQL模式对象,它将SQL名称映射到操作系统中安装的库提供的区域设置。排序规则定义具有*供应商*指定哪个库提供区域设置数据。一个标准的提供者名称是`libc`,它使用操作系统C库提供的区域设置。这些是操作系统提供的大多数工具使用的区域设置。另一个提供者是`重症监护室`,使用外部ICU[](<>)图书馆只有在构建PostgreSQL时配置了对ICU的支持,才能使用ICU区域设置。 由提供的排序规则对象`libc`映射到`立法会`和`LC_CTYPE`设置,由`setlocale()`系统库调用。(顾名思义,整理的主要目的是`立法会`,它控制排序顺序。但在实践中,很少需要有一个`LC_CTYPE`不同于`立法会`,因此,在一个概念下收集这些信息比创建另一个用于设置的基础设施更方便`LC_CTYPE`每个表达式。)还有一个`libc`排序规则与字符集编码相关联(请参阅[第24.3节](multibyte.html))。对于不同的编码,可能存在相同的排序规则名称。 由提供的排序规则对象`重症监护室`映射到ICU图书馆提供的命名拼贴器。ICU不支持单独的“collate”和“ctype”设置,因此它们总是相同的。此外,ICU排序规则独立于编码,因此数据库中给定名称始终只有一个ICU排序规则。 #### 24.2.2.1.标准校勘 在所有平台上,排序规则都命名为`违约`, `C`和`POSIX`都有。根据操作系统支持的不同,可能会提供其他排序规则。这个`违约`排序规则选择`立法会`和`LC_CTYPE`在数据库创建时指定的值。这个`C`和`POSIX`排序规则都指定了“传统C”行为,其中只有ASCII字母`A.`“通过”`Z`“被视为字母,严格按照字符代码字节值进行排序。 此外,SQL标准排序规则名称`ucs_基础`可用于编码`UTF8`.相当于`C`并按Unicode代码点排序。 #### 24.2.2.2.预定义的排序规则 如果操作系统支持在一个程序中使用多个区域设置(`新地`以及相关功能),或者如果配置了对ICU的支持,则在初始化数据库群集时,`initdb`填充系统目录`pg_校勘`根据当时在操作系统中找到的所有区域设置进行排序。 要检查当前可用的区域设置,请使用查询`从pg_排序中选择*`,或命令`\dOS+`在psql中。 ##### 24.2.2.2.1.libc排序规则 例如,操作系统可能会提供一个名为`deu de.utf8`. `initdb`然后创建一个名为`deu de.utf8`用于编码`UTF8`这两者兼而有之`立法会`和`LC_CTYPE`开始`deu de.utf8`。它还将使用`.utf8`标签去掉了名字。因此,您也可以在名称下使用排序规则`德乌德`,这样写起来就不那么麻烦了,而且名称也不那么依赖于编码。然而,请注意,最初的排序规则名称集是依赖于平台的。 由提供的默认排序规则集`libc`直接映射到安装在操作系统中的区域设置,可以使用命令列出这些区域设置`地点-a`.万一`libc`需要具有不同值的排序规则`立法会`和`LC_CTYPE`,或者如果在初始化数据库系统后在操作系统中安装了新的区域设置,则可以使用[创建排序规则](sql-createcollation.html)命令还可以使用[`pg_导入_系统_排序()`](functions-admin.html#FUNCTIONS-ADMIN-COLLATION)作用 在任何特定的数据库中,只有使用该数据库编码的排序规则才有意义。其他参赛作品`pg_校勘`都被忽略了。因此,一个剥离的排序规则名称,如`德乌德`在给定数据库中可以被认为是唯一的,即使它在全球范围内不是唯一的。建议使用剥离的排序规则名称,因为如果您决定更改为另一个数据库编码,则只需更改一件事。然而,请注意`违约`, `C`和`POSIX`无论数据库编码如何,都可以使用排序规则。 PostgreSQL认为不同的排序规则对象是不兼容的,即使它们具有相同的属性。例如, ``` SELECT a COLLATE "C" < b COLLATE "POSIX" FROM test1; ``` 即使`C`和`POSIX`排序规则具有相同的行为。因此,不建议混合使用剥离和非剥离排序规则名称。 ##### 24.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-icu`或`de-CH-x-icu`但在本文中,它们相当于`de-x-icu`.) `und-x-icu`(用于“未定义”) ICU“根”排序。使用此选项可以获得合理的语言不可知排序顺序。 ICU不支持某些(使用频率较低的)编码。如果数据库编码是其中之一,则`pg_校勘`都被忽略了。尝试使用一个将导致“排序规则”de-x-icu“错误,因为编码“WIN874”不存在”。 #### 24.2.2.3.创建新的排序规则对象 如果标准和预定义的排序规则不够,用户可以使用SQL命令创建自己的排序规则对象[创建排序规则](sql-createcollation.html). 标准和预定义的排序规则位于模式中`pg_目录`,就像所有预定义的对象一样。应在用户架构中创建用户定义的排序规则。这也确保了它们由`垃圾场`. ##### 24.2.2.3.1.libc排序规则 可以这样创建新的libc排序规则: ``` CREATE COLLATION german (provider = libc, locale = 'de_DE'); ``` 可接受的精确值`场所`此命令中的子句取决于操作系统。在类Unix系统上,命令`地点-a`将显示一个列表。 由于预定义的libc排序规则已经包括初始化数据库实例时在操作系统中定义的所有排序规则,因此通常不需要手动创建新的排序规则。原因可能是需要不同的命名系统(在这种情况下,请参见[第24.2.2.3.3节](collation.html#COLLATION-COPY))或者如果操作系统已升级以提供新的语言环境定义(在这种情况下,请参见[`pg_导入_系统_排序()`](functions-admin.html#FUNCTIONS-ADMIN-COLLATION)). ##### 24.2.2.3.2.ICU整理 ICU允许在预加载的基本语言+国家/地区集之外定制排序规则`initdb`.鼓励用户定义自己的排序对象,利用这些功能使排序行为符合他们的要求。看见有关ICU区域命名的信息。可接受的名称和属性集取决于特定的ICU版本。 以下是一些例子: `创建排序规则“de-u-co-phonebk-x-icu”(provider=icu,locale=de-u-co-phonebk);`\ `创建排序规则“de-u-co-phonebk-x-icu”(provider=icu,locale=de@collation=电话簿’;` 带有电话簿排序类型的德语排序 第一个示例根据BCP 47使用“语言标记”选择ICU区域设置。第二个示例使用传统的ICU特定区域设置语法。第一种样式是未来的首选样式,但较旧的ICU版本不支持它。 请注意,您可以在SQL环境中随意命名排序规则对象。在本例中,我们遵循预定义排序规则使用的命名样式,该命名样式也遵循BCP 47,但用户定义的排序规则不需要这种命名样式。 `创建排序规则“und-u-co-emoji-x-icu”(provider=icu,locale=und-u-co-emoji);`\ `创建排序规则“und-u-co-emoji-x-icu”(provider=icu,locale='@COLLATION=emoji');` 根据Unicode技术标准#51,使用表情符号排序类型的根排序 观察在传统的ICU语言环境命名系统中,根语言环境是如何由空字符串选择的。 `创建latinlast排序规则(provider=icu,locale=en-u-kr-grek-latn);`\ `创建排序规则latinlast(provider=icu,locale=icu)en@colReorder=grek latn');` 把希腊字母排在拉丁字母之前。(默认值为希腊文之前的拉丁文。) `创建排序规则upperfirst(provider=icu,locale='en-u-kf-upper');`\ `创建排序规则upperfirst(provider=icu,locale=icu)en@colCaseFirst=上“);` 将大写字母排序在小写字母之前。(默认值为小写字母优先。) `创建特殊排序规则(provider=icu,locale=en-u-kf-upper-kr-grek-latn);`\ `创建特殊排序规则(provider=icu,locale=icu)en@colCaseFirst=上;colReorder=grek latn’;` 结合了以上两个选项。 `创建排序规则数字(provider=icu,locale=en-u-kn-true);`\ `创建排序规则数值(provider=icu,locale=icu)en@colNumeric是的);` 数字排序,按数字值对数字序列进行排序,例如:`A-21` \\\< `A-123`(也称为自然排序)。 看见[Unicode技术标准#35](https://www.unicode.org/reports/tr35/tr35-collation.html)和[BCP 47](https://tools.ietf.org/html/bcp47)详细信息。可能的排序规则类型列表(`有限公司`子标签)可以在[CLDR存储库](https://github.com/unicode-org/cldr/blob/master/common/bcp47/collation.xml). 请注意,虽然此系统允许创建“忽略大小写”或“忽略重音”或类似的排序规则(使用`ks`键),为了使此类排序能够真正不区分大小写或重音,还需要声明它们不是*确定性*在里面`创建排序规则`; 看见[第24.2.2.4节](collation.html#COLLATION-NONDETERMINISTIC)。否则,根据排序规则比较相等但在字节方面不相等的任何字符串将根据其字节值进行排序。 ### 笔记 按照设计,ICU将接受几乎任何字符串作为区域名称,并使用其文档中描述的回退过程,将其与它能提供的最接近的区域名称相匹配。因此,如果排序规范是使用给定ICU安装实际上不支持的功能编写的,则不会有直接反馈。因此,建议创建应用程序级测试用例,以检查排序规则定义是否满足要求。 ##### 24.2.2.3.3.复制排序规则 命令[创建排序规则](sql-createcollation.html)还可用于从现有排序规则创建新的排序规则,这对于在应用程序中使用独立于操作系统的排序规则名称、创建兼容性名称或在更可读的名称下使用ICU提供的排序规则非常有用。例如: ``` CREATE COLLATION german FROM "de_DE"; CREATE COLLATION french FROM "fr-x-icu"; ``` #### 24.2.2.4.非确定性排序 排序规则是*确定性*或*不确定性*.确定性排序使用确定性比较,这意味着它仅当字符串由相同的字节序列组成时才认为它们相等。不确定性比较可能会确定字符串是否相等,即使它们由不同的字节组成。典型情况包括不区分大小写的比较、不区分重音的比较,以及不同Unicode标准格式的字符串比较。由排序规则提供者来实际实现这种不敏感的比较;deterministic标志只决定是否使用字节比较来打破联系。另见[Unicode技术标准10](https://www.unicode.org/reports/tr10)有关术语的更多信息。 要创建非确定性排序规则,请指定属性`确定性=错误`到`创建排序规则`,例如: ``` 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-tree不能对使用不确定排序的索引使用重复数据消除。此外,对于不确定的排序规则,某些操作是不可能的,例如模式匹配操作。因此,它们只能在特别需要的情况下使用。 ### 提示 要处理不同Unicode规范化形式的文本,还可以选择使用函数/表达式`规范化`和`标准化了吗`预处理或检查字符串,而不是使用不确定的排序规则。每种方法都有不同的权衡。