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

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 / 9.0 / 8.4
历史版本。 PostgreSQL 11 已结束支持。 2023-11-09. 请参阅 当前版本手册.

F.8. citext #

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

F.8.1. 原理

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

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

这种做法效果尚可,但有几个缺点:

  • 它会让 SQL 语句变得冗长,而且你必须时刻记得同时对列和查询值调用 lower。

  • 除非你创建一个使用 lower 的函数索引,否则它不会使用索引。

  • 如果把列声明为 UNIQUE 或 PRIMARY KEY,隐式生成的索引仍然是大小写敏感的。因此,它既无法用于大小写不敏感搜索,也不能以大小写不敏感的方式强制唯一性。

citext 数据类型允许你在 SQL 查询中省去对 lower 的调用,并允许主键不区分大小写。与 text 一样,citext 也与区域设置相关,这意味着大写字符和小写字符如何匹配取决于数据库 LC_CTYPE 设置的规则。同样,这种行为与在查询中使用 lower 完全一致。但由于这是由数据类型透明地完成的,因此你不必在查询中额外记住任何特殊处理。

F.8.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.8.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.8.4. 限制

  • citext 的大小写折叠行为依赖于数据库的 LC_CTYPE 设置,因此它如何比较值是在创建数据库时确定的。按照 Unicode 标准中的定义,它并不是真正意义上的大小写不敏感。实际上,这意味着只要你对当前排序规则满意,通常也会对 citext 的比较结果满意。但是,如果数据库中存有多种语言的数据,而排序规则只适用于其中某一种语言,那么其他语言的用户可能会发现查询结果并不符合预期。

  • 从 PostgreSQL 9.1 起,你可以为 citext 列或数据值附加 COLLATE 说明。当前,citext 操作符在比较已完成大小写折叠的字符串时,会遵从非默认的 COLLATE 说明;但最初转换为小写这一步,始终仍按数据库的 LC_CTYPE 设置执行(也就是说,等同于给出了 COLLATE "default")。未来的发行版中,这一点可能会改变,从而使这两步都遵循输入的 COLLATE 说明。

  • citext 不如 text 高效,因为操作符函数和 B-树比较函数必须复制数据,并将数据转换为小写后才能进行比较。不过,在需要大小写不敏感匹配时,它仍然比使用 lower 略高效一些。

  • 如果你在某些场景下需要大小写敏感比较,而在另一些场景下又需要大小写不敏感比较,那么 citext 并不会帮上太多忙。标准做法是使用 text 类型,并在需要大小写不敏感比较时手工调用 lower;如果只是偶尔需要这类比较,这种做法是完全可行的。如果你大多数时候都需要大小写不敏感行为,而只是在少数场景下需要大小写敏感比较,那么可以考虑把数据存储为 citext,并在需要大小写敏感比较时显式地把列转换为 text。无论哪种情况,如果你希望这两类搜索都足够快,就都需要建立两个索引。

  • 包含 citext 操作符的模式必须位于当前 search_path 中(通常是 public);如果不在,调用的将是普通的、大小写敏感的 text 操作符。

F.8.5. 作者

David E. Wheeler

灵感来自 Donald Fraser 最初编写的 citext 模块。

报告文档问题

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