【问题标题】:How to make "case-insensitive" query in Postgresql?如何在 Postgresql 中进行“不区分大小写”的查询?
【发布时间】:2011-10-23 17:37:28
【问题描述】:

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

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'

【问题讨论】:

  • 如果您的 Postgres 安装附带了 citext,请尝试使用 citext 类型。这是不区分大小写的文本
  • 对于这个问题的新手,this link 到 postgres 官方文档包含这里给出的所有答案,以及一些其他选项。
  • 请先生将接受的答案重新分配给@Arun 提出的答案。它的复杂性要低得多,而且申请后不会带来一堆麻烦。

标签: postgresql where-clause sql-like case-insensitive


【解决方案1】:

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

试试这个:

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

【讨论】:

  • 重要的是要注意,在谓词列上使用 LOWER(或任何函数)——在本例中为“名称”——将导致任何索引不再可搜索。如果这是一个大的或经常查询的表,那可能会引起麻烦。不区分大小写的排序规则、citext 或基于函数的索引将提高性能。
  • 或者像这样创建一个索引:CREATE INDEX idx_groups_name ON groups lower(name);
  • 如果您希望索引与LIKE 'xxx%' 查询一起使用,也请指定varchar_pattern_ops,即CREATE INDEX ix_groups_name ON groups (lower(name) varchar_pattern_ops)
  • 使用 ILIKE 运算符(如下面的其他答案所示)是一种更简单的方法,即使这是投票最多的答案。
  • 在这里浏览cmets,这里有很多建议建议ILIKE,它会工作,but with slow response。为了根据计算结果快速访问表,我建议任何只是检查这个的人都应该接受接受的答案。查看更多详情 herehere
【解决方案2】:

使用ILIKE 代替LIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'

【讨论】:

  • 请注意,在 Spring Boot 中使用 ILIKE 时,Hibernate 不支持。
  • @AnT 它适用于org.hibernate.dialect.PostgreSQL94Dialect 和 Spring Boot 2.0.6.RELEASE。但 IntelliJ 对此表示不满。
【解决方案3】:

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

  1. 它适用于英语,但并非适用于所有语言。 (也许甚至在 大多数语言。)并非每个小写字母都有对应的 大写字母;不是每个大写字母都有对应的 小写字母。
  2. 使用像 lower() 和 upper() 这样的函数会给你一个顺序 扫描。它不能使用索引。在我的测试系统上,使用 lower() 需要 比可以使用索引的查询长约 2000 倍。 (测试数据的行数略高于 10 万行。)

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

  1. 使用citext module,它主要模仿不区分大小写的数据类型的行为。加载该模块后,您可以通过CREATE INDEX ON groups (name::citext); 创建一个不区分大小写的索引。 (但见下文。)
  2. 使用不区分大小写的排序规则。这是在你初始化一个 数据库。使用不区分大小写的排序规则意味着您可以接受 几乎来自客户端代码的任何格式,您仍然会返回 有用的结果。 (这也意味着您不能进行区分大小写的查询。Duh。)
  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:这不应该是一个问题,因为它会是两个不同的字符串(把它想象成col = 'a'col = 'b')。关于#2:正如您所说,您可以在表达式上创建索引,所以这不是一个真正的问题。但我同意您的观点,即更改排序规则很可能是最好的解决方案。
  • 有人能告诉我什么不区分大小写的排序规则是 PostgreSQL 内置排序规则吗?我认为这是一种选择,但在网上找不到有关 Postgres 不区分大小写排序规则的任何信息?
  • @AnupShah:不,我不是这么说的。我没有在 Windows 上运行 PostgreSQL。 The 9.4 docs say this:“在所有平台上,都可以使用名为 default、C 和 POSIX 的排序规则。根据操作系统支持,可能会提供其他排序规则。”您可以通过 select * from pg_collation; 查看 PostgreSQL 认为哪些排序规则可用。
  • @Matthieu:这是对我所知道的主题的最佳介绍(和警告):Edge Cases to Keep in Mind. Part 1 – Text
  • @Matthieu: The Unicode FAQ 读起来也很有趣。这是Why's there no unique uppercase character for . . .
【解决方案4】:

您可以使用ILIKE。即

SELECT id FROM groups where name ILIKE 'administrator'

【讨论】:

  • 它对我来说正确且工作正常,我使用的是 MAC OS X(Mountain Lion)。
  • 这会起作用,但响应缓慢。为了根据计算结果快速访问表,我建议使用lower 函数。查看更多details
  • @AfolabiOlaoluwaAkinwumi 从根本上说,这归结为您是否在搜索过滤已知值相反的结果。在后一种情况下,应在数据级别保留一个统一的情况,以允许相等运算符工作。 [个人建议类型码值大写帕斯卡]
【解决方案5】:

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

【讨论】:

  • 这里要注意的是恶意用户输入。如果您运行类似email ILIKE 'user-input-email-here' 的查询,请确保转义用户输入。否则,人们可以输入匹配任何内容的字符,例如 %。
  • @MattDeLeon 嗨。说得好。但我只想问你,如果我使用ILIKEprepared statements 这会保护我免受sql injection 的伤害吗?
  • "根据活动区域设置,可以使用关键字 ILIKE 代替 LIKE 使匹配不区分大小写。这不在 SQL 标准中,而是 PostgreSQL 扩展。"在 9.3 中像魅力一样工作
  • ILIKE 比 lower(column_name) like %expression% 慢。
  • @PatrykImosa:您能否详细说明或展示 ILIKE 变慢的示例?
【解决方案6】:

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

SELECT id FROM groups where name ~* 'administrator'

SELECT 'asd' ~* 'AsD' 返回t

【讨论】:

  • 我遇到了同样的问题,我需要在我的 PostgreSQL 数据库上进行不区分大小写的搜索。我考虑将用户输入字符串转换为正则表达式。现在,使用 ~* 而不是 = 或 LIKE 效果很好!我不需要创建新的索引、列或其他任何东西。当然,正则表达式搜索比直接字节比较慢,但我认为对性能的影响不会比处理两组数据(一个小写或大写仅用于搜索,然后必须检索相应的原始数据)大得多另一组的数据)。而且,这样更干净!
  • 很好,但是例如如何使用 regexp_matches() 呢?
  • 根据postgres docs:操作符~~相当于LIKE,~~*相当于ILIKE。还有 !~~ 和 !~~* 运算符分别代表 NOT LIKE 和 NOT ILIKE。所有这些运算符都是 PostgreSQL 特定的。
  • 我遇到了一个问题,当括号包含在文本中时,它不起作用。比如:“代码(LC)”
  • 遇到特殊字符问题。
【解决方案7】:

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

SELECT id FROM groups WHERE name ~* 'adm'

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

【讨论】:

  • 嗨,罗宾,欢迎来到 SO。詹姆斯布朗的回答已经提出了这个解决方案。此外,您提出的答案不会以任何方式利用正则表达式。
  • ~* 并不是完全不区分大小写的匹配。它是正则表达式模式匹配。在您的示例中,如果 db 包含 ADMwhere name ~* 'Adm'where name ~* 'Ad' 将产生结果。请改用ILIKE
【解决方案8】:

ILIKE 在这种情况下工作:

SELECT id 
  FROM groups
 WHERE name ILIKE 'Administrator'

【讨论】:

    【解决方案9】:
    select id from groups where name in ('administrator', 'ADMINISTRATOR', 'Administrator')
    

    【讨论】:

    • 请在您的答案中添加一些解释,以便其他人可以从中学习
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 2021-08-05
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多