citext
模块提供了一个不区分大小写的字符字符串类型,citext
。本质上,它在比较值时内部调用 lower
。除此之外,它的行为几乎与 text
完全相同。
请考虑使用非确定性排序规则(请参见第 23.2.2.4 节)来代替此模块。它们可以用于不区分大小写的比较、不区分重音符号的比较和其他组合,并且它们可以正确处理更多 Unicode 特殊情况。
该模块被认为是“受信任的”,也就是说,具有当前数据库的 CREATE
权限的非超级用户可以安装它。
在 PostgreSQL 中执行不区分大小写匹配的标准方法是在比较值时使用 lower
函数,例如
SELECT * FROM tab WHERE lower(col) = LOWER(?);
这种方法效果不错,但是存在一些缺点
它会使您的 SQL 语句冗长,而且您总是必须记住在列和查询值上都使用 lower
。
它不会使用索引,除非您使用 lower
创建函数索引。
如果您将列声明为 UNIQUE
或 PRIMARY KEY
,则隐式生成的索引是区分大小写的。因此,它对不区分大小写的搜索毫无用处,并且不会以不区分大小写的方式强制执行唯一性。
citext
数据类型允许您在 SQL 查询中消除对 lower
的调用,并允许主键不区分大小写。citext
具有区域设置感知能力,就像 text
一样,这意味着大写和小写字符的匹配取决于数据库的 LC_CTYPE
设置规则。同样,此行为与在查询中使用 lower
的行为相同。但是,由于它是由数据类型透明地完成的,因此您不必记住在查询中执行任何特殊操作。
这是一个简单的使用示例
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
并且查询为 Larry
,SELECT
语句也会返回一个元组。
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
。
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
来正确处理这种情况。
如果您发现文档中的任何内容不正确、与您对特定功能的体验不符或需要进一步澄清,请使用此表单报告文档问题。