Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

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

F.9.1. 基本原理
F.9.2. 使用方法
F.9.3. 字符串比较行为
F.9.4. 限制
F.9.5. 作者

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 的调用,并允许主键不区分大小写。citext 是区分语言环境的,就像 text 一样,这意味着大小写字符的匹配取决于数据库的 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 起,您可以将 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. 作者 #

大卫·E·惠勒

灵感来自 Donald Fraser 创作的原始 citext 模块。