选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1
历史版本PostgreSQL 9.1 已于 2016 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

22.2. 排序规则支持 #

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

22.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;

解析器无法确定应当应用哪个排序规则,因为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";

22.2.2. 管理排序规则

排序规则是一个 SQL 模式对象,它把某个 SQL 名称映射到操作系统的区域设置。 具体来说,它对应于LC_COLLATELC_CTYPE 的一种组合。(顾名思义,排序规则的主要用途是设置控制排序顺序的 LC_COLLATE。但在实践中,很少有必要让 LC_CTYPELC_COLLATE不同,因此把 二者归为一个概念,比再建立一套为每个表达式设置LC_CTYPE 的机制更方便。)此外,排序规则还与某种字符集编码绑定(见第 22.3 节)。 同一个排序规则名称可能会在不同编码中出现。

所有平台都提供名为 defaultCPOSIX 的排序规则。根据操作系统支持情况,还可能提供其他排序规则。default 排序规则选择创建数据库时指定的 LC_COLLATELC_CTYPE 值。CPOSIX 排序规则都采用传统 C行为,仅将 ASCII 字母 AZ 视为字母,并严格按字符编码的字节值排序。

如果操作系统支持在单个程序中使用多个区域设置(newlocale 及相关函数),那么在初始化数据库集簇时, initdb会根据当时在操作系统中发现的所有区域设置,用 排序规则填充系统目录pg_collation。例如,操作系统可能提供一个名为de_DE.utf8的区域设 置。initdb随后会为UTF8编码创建 一个名为de_DE.utf8的排序规则,其 LC_COLLATELC_CTYPE都设置为 de_DE.utf8。它还会再创建一个从名称中去掉 .utf8标签的排序规则。因此,你也可以使用 de_DE这个名称来使用该排序规则,这样写起来更方便, 且名称与编码的耦合更小。不过请注意,初始排序规则名称集合仍然取决于平 台。

如果需要一个LC_COLLATELC_CTYPE取值 不同的排序规则,可以使用CREATE COLLATION命令创建新 的排序规则。该命令也可以用来从一个已有排序规则创建新的排序规则,这有助 于在应用中使用与操作系统无关的排序规则名称。

在任何特定数据库中,只有使用该数据库编码的排序规则才有意义。 pg_collation中的其他条目会被忽略。因此,像 de_DE这样去掉编码后缀的排序规则名称,在某个给定数 据库内可以视为唯一,即使它在全局范围内并不唯一。建议使用这种去掉后缀 的排序规则名称,因为如果你决定改用另一种数据库编码,需要改动的地方会 更少。不过要注意, defaultCPOSIX 排序规则不受数据库编码影响,始终都可以使用。

PostgreSQL即使面对具有相同属性的不同排序规 则对象,也会把它们视为不兼容。例如:

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

即使CPOSIX排序规则的行为完全 相同,这仍然会报错。因此,不建议混用去掉后缀和保留后缀的排序规则名 称。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。