支持的版本:当前 (17) / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4

F.9. citext — 一个大小写不敏感的字符串类型 #

citext 模块提供了一个大小写不敏感的字符串类型 citext。本质上,它在比较值时内部调用 lower。除此之外,它的行为几乎与 text 完全相同。

提示

考虑使用不确定性的排序规则(请参见 第 23.2.2.4 节)而不是此模块。它们可以用于大小写不敏感的比较、重音不敏感的比较以及其他组合,并且它们可以正确处理更多的 Unicode 特殊情况。

此模块被认为是 受信任的,也就是说,具有当前数据库 CREATE 权限的非超级用户可以安装它。

F.9.1. 原理 #

PostgreSQL 中进行大小写不敏感匹配的标准方法是在比较值时使用 lower 函数,例如

SELECT * FROM tab WHERE lower(col) = LOWER(?);

这种方法效果还不错,但存在一些缺点

  • 它使您的 SQL 语句变得冗长,并且您总是必须记得在列和查询值上都使用 lower

  • 它不会使用索引,除非您使用 lower 创建函数索引。

  • 如果您将列声明为 UNIQUEPRIMARY KEY,则隐式生成的索引是区分大小写的。因此,它对于大小写不敏感的搜索没有用处,并且它不会强制执行大小写不敏感的唯一性。

citext 数据类型允许您消除 SQL 查询中对 lower 的调用,并允许主键不区分大小写。citexttext 一样是区域设置感知的,这意味着大写字符和小写字符的匹配取决于数据库的 LC_CTYPE 设置规则。同样,此行为与在查询中使用 lower 的行为相同。但是,由于它是由数据类型透明地完成的,因此您不必记住在查询中执行任何特殊操作。

F.9.2. 如何使用它 #

这是一个简单的使用示例

CREATE TABLE users (
    nick CITEXT PRIMARY KEY,
    pass TEXT   NOT NULL
);

INSERT INTO users VALUES ( 'larry',  sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Tom',    sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Damian', sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'NEAL',   sha256(random()::text::bytea) );
INSERT INTO users VALUES ( 'Bjørn',  sha256(random()::text::bytea) );

SELECT * FROM users WHERE nick = 'Larry';

即使 nick 列设置为 larry 并且查询的是 LarrySELECT 语句也会返回一个元组。

F.9.3. 字符串比较行为 #

citext 通过将每个字符串转换为小写(如同调用 lower 一样)然后正常比较结果来执行比较。因此,例如,如果 lower 为两个字符串生成相同的结果,则认为这两个字符串相等。

为了尽可能地模拟不区分大小写的排序规则,存在一些特定于 citext 的字符串处理运算符和函数版本。因此,例如,正则表达式运算符 ~~* 在应用于 citext 时表现出相同的行为:它们都进行大小写不敏感的匹配。对于 !~!~*,以及 LIKE 运算符 ~~~~*,以及 !~~!~~* 也是如此。如果您想进行区分大小写的匹配,则可以将运算符的参数强制转换为 text

类似地,如果以下所有函数的参数是 citext,则它们都会执行大小写不敏感的匹配

  • regexp_match()

  • regexp_matches()

  • regexp_replace()

  • regexp_split_to_array()

  • regexp_split_to_table()

  • replace()

  • split_part()

  • strpos()

  • translate()

对于 regexp 函数,如果要进行区分大小写的匹配,可以指定 c 标志来强制进行区分大小写的匹配。否则,如果想要区分大小写的行为,必须在使用这些函数之一之前强制转换为 text

F.9.4. 局限性 #

  • citext 的大小写折叠行为取决于数据库的 LC_CTYPE 设置。因此,它如何比较值是在创建数据库时确定的。按照 Unicode 标准的定义,它不是真正的大小写不敏感。实际上,这意味着,只要您对排序规则感到满意,您就应该对 citext 的比较感到满意。但是,如果您的数据库中存储了不同语言的数据,则如果排序规则是针对另一种语言的,则一种语言的用户可能会发现他们的查询结果与预期不符。

  • PostgreSQL 9.1 开始,您可以将 COLLATE 规范附加到 citext 列或数据值。目前,citext 运算符在比较大小写折叠的字符串时会遵循非默认的 COLLATE 规范,但是初始折叠为小写始终是根据数据库的 LC_CTYPE 设置完成的(即,如同给定了 COLLATE "default" 一样)。在未来的版本中可能会更改此行为,以便两个步骤都遵循输入的 COLLATE 规范。

  • citext 不如 text 高效,因为运算符函数和 B 树比较函数必须复制数据并将其转换为小写进行比较。此外,只有 text 可以支持 B 树去重。但是,citext 比使用 lower 来获得大小写不敏感的匹配稍微高效一些。

  • 如果您需要在某些上下文中进行区分大小写的比较,而在其他上下文中进行不区分大小写的比较,则 citext 没有太大帮助。标准的答案是使用 text 类型,并在需要进行不区分大小写的比较时手动使用 lower 函数;如果只需要偶尔进行不区分大小写的比较,则此方法效果很好。如果您在大多数时间都需要不区分大小写的行为,而偶尔需要区分大小写的行为,请考虑将数据存储为 citext,并在需要进行区分大小写的比较时显式地将列强制转换为 text。在任何一种情况下,如果您希望两种类型的搜索都很快,则需要两个索引。

  • 包含 citext 运算符的模式必须位于当前的 search_path 中(通常是 public);如果不是,则将调用普通的区分大小写的 text 运算符。

  • 用于比较的小写字符串方法不能正确处理某些 Unicode 特殊情况,例如当一个大写字母有两个小写字母等效项时。Unicode 为此区分了大小写映射大小写折叠。使用不确定性的排序规则而不是 citext 来正确处理它。

F.9.5. 作者 #

David E. Wheeler

受 Donald Fraser 的原始 citext 模块的启发。

提交更正

如果您在文档中看到任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用此表单报告文档问题。