↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1
历史版本。 PostgreSQL 9.5 已结束支持。 2021-02-11. 请参阅 当前版本手册.

22.2. 排序规则支持 #

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

22.2.1. 概念

从概念上讲,每个支持排序规则的数据类型的表达式都有一个排序规则。(内置的支持排序规则的数据类型包括text、varchar和char。用户定义的基础类型也可以标记为支持排序规则,当然,建立在支持排序规则的数据类型之上的域也支持排序规则。)如果表达式是列引用,则该表达式的排序规则就是该列定义的排序规则。如果表达式是常量,则其排序规则就是该常量数据类型的默认排序规则。更复杂表达式的排序规则则按下文所述,从其输入表达式的排序规则推导出来。

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

当数据库系统必须执行排序或字符分类时,它会使用输入表达式的排序规则。这例如发生在ORDER BY子句以及函数或操作符调用(如 <)中。应用于ORDER BY子句的排序规则就是排序键的排序规则。应用于函数或操作符调用的排序规则则按下文所述,从参数中推导出来。除了比较操作符之外,在大小写之间进行转换的函数(例如lower、upper和 initcap)、模式匹配操作符,以及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_COLLATE和LC_CTYPE 的一种组合。(顾名思义,排序规则的主要用途是设置控制排序顺序的 LC_COLLATE。但在实践中,很少有必要让 LC_CTYPE和LC_COLLATE不同,因此把二者归为一个概念,比再建立一套为每个表达式设置LC_CTYPE 的机制更方便。)此外,排序规则还与某种字符集编码绑定(见第 22.3 节)。同一个排序规则名称可能会在不同编码中出现。

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

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

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

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

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

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

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

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.