PostgreSQL:如何进行“不区分大小写”查询


338

有什么方法可以在PostgreSQL中编写不区分大小写的查询,例如,我希望以下3个查询返回相同的结果。

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'

如果citext随Postgres安装一起提供,请尝试citext类型。这是不区分大小写的文本
迈克尔·布埃诺

2
对于这个问题的新手,此指向 postgres官方文档的链接包含此处给出的所有答案以及其他一些选项。
Parthian Shot

主席先生,请重新分配对@Arun做出的答复。它不那么复杂,并且在应用后不会带来很多麻烦。
zeliboba

Answers:


451

比较之前,请使用LOWER函数将字符串转换为小写。

尝试这个:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')

92
重要的是要注意,在谓词列上使用LOWER(或任何函数)(在本例中为“ name”)将导致不再可检索任何索引。如果这是一个很大的表或经常查询的表,则可能会造成麻烦。不区分大小写的排序规则,citext或基于函数的索引将提高性能。
约旦

108
或只是创建一个像这样的索引:CREATE INDEX idx_groups_name ON组lower(name);
丹尼尔(Daniel)

19
还指定varchar_pattern_ops是否要让索引与LIKE 'xxx%'查询一起使用,即CREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops)
sayap 2011年

10
使用ILIKE运算符(如下文其他答案所示)是一种更简单的方法,即使这是最受好评的答案。
Ryan

5
通过这里的评论,这里有很多建议表明ILIKE,它将起作用but with slow response。为了基于计算结果快速访问表,我建议任何仅检查此内容的人都应该接受公认的答案。在这里这里
Afolabi Olaoluwa Akinwumi


134

最常见的方法是小写或大写搜索字符串和数据。但这有两个问题。

  1. 它可以使用英语,但不能使用所有语言。(甚至在大多数语言中也可能没有。)并非每个小写字母都有一个对应的大写字母。并非每个大写字母都有对应的小写字母。
  2. 使用lower()和upper()之类的函数将为您提供顺序扫描。它不能使用索引。在我的测试系统上,使用lower()所花费的时间比可以使用索引的查询长2000倍。(测试数据有超过10万行。)

至少有三种不常用的解决方案可能更有效。

  1. 使用citext模块,该模块主要模拟不区分大小写的数据类型的行为。加载该模块后,您可以通过创建不区分大小写的索引CREATE INDEX ON groups (name::citext);。(但请参见下文。)
  2. 使用不区分大小写的排序规则。初始化数据库时设置。使用不区分大小写的排序规则意味着您可以接受来自客户端代码的几乎任何格式,并且仍然会返回有用的结果。(这也意味着您不能执行区分大小写的查询。Du。)
  3. 创建一个功能索引。使用创建一个小写索引CREATE INDEX ON groups (LOWER(name));。完成此操作后,您可以通过诸如之类的查询来利用索引SELECT id FROM groups WHERE LOWER(name) = LOWER('ADMINISTRATOR');,但是SELECT id FROM groups WHERE LOWER(name) = 'administrator';您必须记住要使用LOWER()。

citext模块未提供真正的不区分大小写的数据类型。相反,它的行为就像每个字符串都是小写的一样。也就是说,它的行为就像您已lower()在每个字符串上调用一样,如上面的数字3所示。好处是程序员不必记住小写的字符串。但是,在决定使用citext之前,您需要阅读文档中的“字符串比较行为”和“限制”部分。


1
关于#1:这应该不成问题,因为它将是两个不同的字符串(请像do col = 'a'和那样思考col = 'b')。关于#2:正如您所说,您可以在表达式上创建索引,因此这并不是真正的问题。但我同意您的看法,更改排序规则最有可能是最佳解决方案。
文森特·萨瓦德

5
有人可以告诉我PostgreSQL内置排序规则不区分大小写吗?我将其视为一种选择,但是在网上找不到有关Postgres不区分大小写的排序规则的信息吗?
khorvat 2013年

1
@AnupShah:不,我不是在说这个。我没有在Windows上运行PostgreSQL。9.4文档说:“在所有平台上,都可以使用名为default,C和POSIX的排序规则。根据操作系统的支持,可能还可以使用其他排序规则。” 您可以查看PostgreSQL认为哪些排序规则可用select * from pg_collation;
Mike Sherrill'Cat Recall'15

1
@Matthieu:这是对我所知道的主题的最佳介绍(和警告):要牢记的边缘案例。第1部分–文本
Mike Sherrill'Cat Recall'17


95

您可以使用ILIKE。即

SELECT id FROM groups where name ILIKE 'administrator'

它对我来说是正确的并且工作正常,我正在使用MAC OS X(Mountain Lion)。
ADJ

5
这将起作用,但响应速度慢。为了基于计算结果快速访问表,我建议使用该lower函数。查看更多详细信息
Afolabi Olaoluwa Akinwumi

1
从根本上说,@ AfolabiOlaoluwaAkinwumi取决于您是否要搜索过滤 已知值相对的结果。在后一种情况下,应在数据级别上保留一个统一的情况,以使相等运算符起作用。[个人建议是键入代码值的大写字母]
Chris Marisic '17

53

您也可以阅读ILIKE关键字。尽管它不符合SQL标准,但有时可能会非常有用。请参阅此处以获取更多信息:http : //www.postgresql.org/docs/9.2/static/functions-matching.html


9
需要注意的是恶意用户输入。如果运行类似的查询email ILIKE 'user-input-email-here',请确保转义用户输入。否则,人们可以输入匹配任何字符的字符,例如%。
马特·德莱昂

2
@MattDeLeon嗨。说得好。但是我只是想问你,如果我使用ILIKEprepared statements这会保护我免受伤害sql injection吗?
slevin 2013年

不确定,我想您想将转义字符串发送到准备好的语句。
马特·德利昂

1
“根据活动的语言环境,可以使用关键字ILIKE代替LIKE来使匹配不区分大小写。这不是SQL标准,而是PostgreSQL扩展。” 像9.3中的魅力一样工作
Aleksey Deryagin 2014年

1
ILIKE比慢lower(column_name) like %expression%
Patryk Imosa

28

您还可以使用POSIX正则表达式,例如

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' 退货 t


1
我遇到了同样的问题,我需要在PostgreSQL数据库上进行不区分大小写的搜索。我考虑过将用户输入的字符串转换为正则表达式。现在,使用〜*代替=或LIKE非常有效!我不需要创建新的索引,列或任何其他内容。当然,正则表达式搜索比直接字节比较要慢,但是我认为对性能的影响不会比必须处理两组数据(仅用于搜索的一组小写或大写的数据,然后必须检索相应的原始数据)大得多另一组的数据)。此外,这更干净!
赛博骑士

1
很好,但是例如如何使用regexp_matches()?
WKT

根据postgres docs:运算符~~等同于LIKE,~~ *等同于ILIKE。还有!~~和!~~ *运算符分别表示NOT LIKE和NOT ILIKE。所有这些运算符都是PostgreSQL特定的。
sh4

当方括号包含在文本中时,我遇到了一个问题,它无法正常工作。例如:“代码(LC)”
Oshan Wisumperuma

8

使用~*INSTR的功能可以大大提高性能。

SELECT id FROM groups WHERE name ~* 'adm'

返回名称包含OR的行等于“ adm”。


1
嗨,罗宾,欢迎来到。James Brown的答案已经提出了此解决方案。此外,您提出的答案不会以任何方式使用正则表达式。
拉斐尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.