PostgreSQL:如何进行"不区分大小写"的查询

Jam*_*ame 295 postgresql

有没有办法在PostgreSQL中编写不区分大小写的查询,例如我希望以下3个查询返回相同的结果.

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'
Run Code Online (Sandbox Code Playgroud)

Cha*_*ndu 409

在比较之前使用LOWER函数将字符串转换为小写.

试试这个:

SELECT id 
  FROM groups
 WHERE LOWER(name)=LOWER('Administrator')
Run Code Online (Sandbox Code Playgroud)

  • 或者只是创建一个这样的索引:CREATE INDEX idx_groups_name ON groups lower(name); (101认同)
  • 重要的是要注意在谓词列上使用LOWER(或任何函数) - 在本例中为"name" - 将导致任何索引不再可搜索.如果这是一个大型或经常查询的表,那可能会造成麻烦.不区分大小写的排序规则,citext或基于函数的索引将提高性能. (81认同)
  • 如果希望索引与`LIKE'xxx%''查询一起使用,即``CREATE INDEX ix_groups_name ON groups(lower(name)varchar_pattern_ops)`,也可以指定`varchar_pattern_ops`. (16认同)
  • 使用ILIKE运算符(如下面的其他答案所示)是一种更简单的方法,即使这是最有效的答案. (9认同)
  • 要添加@miR的评论:虽然ILIKE方法在语法上要简单得多,但它永远不会尝试使用索引 - 因此,如果性能对您非常重要,请考虑使用Chandu的解决方案w/Daniel和sayap所展示的索引. (3认同)
  • 通过这里的评论,这里有很多建议建议使用“ ILIKE”,它会起作用,但响应速度很慢。为了基于计算结果快速访问表,我建议任何仅检查此内容的人都应该接受公认的答案。查看更多详细信息[此处](https://www.postgresql.org/docs/current/static/indexes-expressional.html)和[此处](http://stackoverflow.com/a/11278943/5614748) (3认同)
  • @cyberspy 指出缺陷很容易,但真正提供帮助并提供一些替代方法要困难得多? (3认同)
  • 这是否解决了“土耳其问题”?http://www.i18nguy.com/unicode/turkish-i18n.html (2认同)
  • 这是*错误的*,大小写转换很大程度上是区域设置特定的事情,您不能只将字符串转换为小写/大写并比较它们,某些字符串可能有多个小写变体,因此不会匹配。 (2认同)

Moh*_*uzi 183

使用ILIKE而不是LIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'
Run Code Online (Sandbox Code Playgroud)

  • 请注意,在 Spring Boot 中使用时,Hibernate 不支持“ILIKE”。 (7认同)
  • 实际上,“ILIKE”是最简单的答案,但并不是所有情况下的“实际”答案。`ILIKE` 是 Postgres 的非标准扩展,它的执行速度非常慢。使用“LOWER”函数以及适当的索引的公认答案将表现得更好,并将受到所有客户端库和 ORMS 的支持。这取决于您的特定用例。 (6认同)
  • 这是实际的答案,接受的答案是一个 hack (3认同)
  • @AnT 它适用于“org.hibernate.dialect.PostgreSQL94Dialect”和 Spring Boot 2.0.6.RELEASE。但 IntelliJ 对此有所抱怨。 (2认同)

Mik*_*ll' 119

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

  1. 它适用于英语,但不适用于所有语言.(也许在大多数语言中都没有.)并非每个小写字母都有相应的大写字母; 并非每个大写字母都有相应的小写字母.
  2. 使用lower()和upper()等函数可以进行顺序扫描.它不能使用索引.在我的测试系统上,使用lower()比使用索引的查询长约2000倍.(测试数据有超过10万行.)

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

  1. 使用citext模块,它主要模仿不区分大小写的数据类型的行为.加载该模块后,您可以创建不区分大小写的索引CREATE INDEX ON groups (name::citext);.(但见下文.)
  2. 使用不区分大小写的排序规则.初始化数据库时设置此项.使用不区分大小写的排序规则意味着您可以接受来自客户端代码的任何格式,并且您仍将返回有用的结果.(这也意味着你不能做区分大小写的查询.杜.)
  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之前,您需要阅读文档中的"字符串比较行为"和"限制"部分.

  • 有人能告诉我PostgreSQL内置排序规则中哪些不区分大小写的排序规则?我认为这是一个选项,但在网上找不到Postgres不区分大小写的排序规则? (5认同)

小智 93

你可以用ILIKE.即

SELECT id FROM groups where name ILIKE 'administrator'
Run Code Online (Sandbox Code Playgroud)

  • 这会有效,但反应迟钝.为了根据计算结果快速访问表,我建议使用`lower`函数.查看更多[详情](https://www.postgresql.org/docs/current/static/indexes-expressional.html) (4认同)
  • @AfolabiOlaoluwaAkinwumi 从根本上说,这取决于您是否正在**搜索** 与**过滤** *已知* 值相反的结果。在后一种情况下,应在数据级别保留一个统一的案例,以允许相等运算符工作。[个人建议是类型代码值的上帕斯卡大小写] (2认同)

Pri*_*mre 51

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

  • 这里需要注意的是恶意用户输入.如果您运行查询,例如`email ILIKE'user-input-email-here'`,请确保转义用户输入.否则,人们可以输入匹配任何内容的%字符. (8认同)
  • @MattDeLeon嗨。说得好。但是我只想问你,如果我使用ILIKE和prepared statement可以保护我免受sql注入的侵害? (2认同)
  • ILIKE 比 `lower(column_name) like %expression%` 慢。 (2认同)

小智 30

使用ILIKE

select id from groups where name ILIKE 'adminstration';
Run Code Online (Sandbox Code Playgroud)

如果你来的expressjs背景和名称是一个变量使用

select id from groups where name ILIKE $1;
Run Code Online (Sandbox Code Playgroud)


小智 25

你也可以使用POSIX正则表达式,比如

SELECT id FROM groups where name ~* 'administrator'
Run Code Online (Sandbox Code Playgroud)

SELECT 'asd' ~* 'AsD' t

  • 使用〜*会影响性能吗? (3认同)
  • 根据 postgres 文档: 运算符 ~~ 相当于 LIKE,而 ~~* 对应于 ILIKE。还有 !~~ 和 !~~* 运算符,分别表示 NOT LIKE 和 NOT ILIKE。所有这些运算符都是 PostgreSQL 特定的。 (2认同)

小智 11

在这种情况下ILIKE工作:

SELECT id 
  FROM groups
 WHERE name ILIKE 'Administrator'
Run Code Online (Sandbox Code Playgroud)


小智 6

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

SELECT id FROM groups WHERE name ~* 'adm'
Run Code Online (Sandbox Code Playgroud)

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

  • 嘿,罗宾,欢迎来到 SO。James Brown 的回答已经提出了这个解决方案。此外,您提出的答案不会以任何方式利用正则表达式。 (3认同)