F.9. citext

citext模块提供了不区分大小写的字符串类型citext。本质上,当比较值时,它内部调用lower。否则,它的行为几乎与text类似。

F.9.1. Rationale

在 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',  md5(random()::text) );
INSERT INTO users VALUES ( 'Tom',    md5(random()::text) );
INSERT INTO users VALUES ( 'Damian', md5(random()::text) );
INSERT INTO users VALUES ( 'NEAL',   md5(random()::text) );
INSERT INTO users VALUES ( 'Bjørn',  md5(random()::text) );

SELECT * FROM users WHERE nick = 'Larry';

即使nick列设置为larry且查询是针对Larry的,SELECT语句也将返回一个 Tuples。

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. Limitations

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

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

  • citext不如text高效,因为运算符功能和 B 树比较功能必须复制数据并将其转换为小写以便进行比较。但是,与使用lower进行不区分大小写的匹配相比,此方法效率更高。

  • 如果您需要数据在某些情况下区分大小写,而在其他情况下不区分大小写,则citext并没有多大帮助。标准答案是使用text类型,并在需要区分大小写的比较时手动使用lower函数。如果仅很少需要不区分大小写的比较,则可以正常工作。如果大多数情况下需要不区分大小写的行为,并且不经常区分大小写,请考虑将数据存储为citext,并在需要区分大小写的比较时将列显式转换为text。无论哪种情况,如果都希望两种类型的搜索都快,则将需要两个索引。

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

F.9.5. Author

戴维·惠勒<[email protected]>

受到 Donald Fraser 最初的citext模块的启发。