2025年9月25日: PostgreSQL 18 发布!
支持版本: 当前 (18) / 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';

SELECT 语句将返回一个元组,尽管 nick 列设置为 larry 并且查询是针对 Larry 的。

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()

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

F.9.4. 限制 #

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

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

  • citext 的效率不如 text,因为运算符函数和 B-tree 比较函数必须复制数据并将其转换为小写进行比较。此外,只有 text 支持 B-Tree 重复数据删除。但是,citext 比使用 lower 进行不区分大小写的匹配效率稍高。

  • 如果您需要在某些上下文中区分大小写,而在其他上下文中不区分大小写地比较数据,那么 citext 帮助不大。标准答案是使用 text 类型,并在需要不区分大小写比较时手动调用 lower 函数;如果仅偶尔需要不区分大小写比较,这效果还不错。如果您大部分时间需要不区分大小写行为,而偶尔需要区分大小写,请考虑将数据存储为 citext,并在需要区分大小写比较时显式将该列转换为 text。在这两种情况下,如果您希望两种搜索都快速,您都需要两个索引。

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

  • 为了比较而将字符串转换为小写的方法不能正确处理某些 Unicode 特殊情况,例如当一个大写字母有两个小写字母对应的情况。Unicode 因此区分“大小写映射”和“大小写折叠”。请使用非确定性排序规则而不是 citext 来正确处理这种情况。

F.9.5. 作者 #

David E. Wheeler <>

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

提交更正

如果您在文档中发现任何不正确的内容、与您在使用特定功能时的体验不符或需要进一步澄清之处,请使用此表格报告文档问题。