如何在Postgresql中进行“不区分大小写”的查询?

问题描述 投票:0回答:16

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

SELECT id FROM groups where name='administrator'

SELECT id FROM groups where name='ADMINISTRATOR'

SELECT id FROM groups where name='Administrator'
postgresql where-clause sql-like case-insensitive
16个回答
705
投票

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

试试这个:

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

548
投票

使用

ILIKE
代替
LIKE

SELECT id FROM groups WHERE name ILIKE 'Administrator'

172
投票

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

  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 之前,您需要阅读文档中的“字符串比较行为”和“限制”部分。


138
投票

您可以使用

ILIKE
。即

SELECT id FROM groups where name ILIKE 'administrator'

61
投票

您还可以阅读

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


40
投票

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

SELECT id FROM groups where name ~* 'administrator'

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


30
投票

使用

ILIKE

select id from groups where name ILIKE 'adminstration';

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

select id from groups where name ILIKE $1;

15
投票

使用

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

SELECT id FROM groups WHERE name ~* 'adm'

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


11
投票

喜欢这种情况下的工作:

SELECT id 
  FROM groups
 WHERE name ILIKE 'Administrator'

4
投票

现有答案都不正确。

土耳其语有字母

I
的多种表示形式,从区分大小写的角度来看,这些表示形式是相同的。比较这些字符的小写或大写形式将返回 false。

格鲁吉亚语有一个没有大写对应的字符

,以及一个没有对应的小写字母的字符
。如果你深入研究
String.equalsIgnoreCase()
的 Java 实现,你会发现以下代码片段:

// Case insensitive comparison of two code points
private static int compareCodePointCI(int cp1, int cp2) {
    // try converting both characters to uppercase.
    // If the results match, then the comparison scan should
    // continue.
    cp1 = Character.toUpperCase(cp1);
    cp2 = Character.toUpperCase(cp2);
    if (cp1 != cp2) {
        // Unfortunately, conversion to uppercase does not work properly
        // for the Georgian alphabet, which has strange rules about case
        // conversion.  So we need to make one last check before
        // exiting.
        cp1 = Character.toLowerCase(cp1);
        cp2 = Character.toLowerCase(cp2);
        if (cp1 != cp2) {
            return cp1 - cp2;
        }
    }
    return 0;
}

此外,如果您想以不区分大小写的方式比较字符串,您可能还想消除其他差异。您可以使用称为“文本规范化”的过程将文本转换为规范形式,去除重音符号、标点符号、显示相同但具有不同值的字符以及不可见字符。

我个人处理这个问题的方式是为我想要搜索的每一列存储两个表示:

  • foobar_display
    对应于用户输入的原始值,用于显示目的。
  • foobar_compare
    用于搜索和比较目的。

每次向数据库中插入一行时,我都会将

foobar_display
转换为 foobar_compare
using a [text normalization library](https://github.com/slugify/slugify). I store both values, and any time a user tries searching for a value I use
foobar_compare` 以检测部分或完全匹配。

最后,我添加了一个针对

foobar_compare
的唯一约束来消除不需要的重复项。


3
投票

如果您不仅想要大写/小写还想要变音符号,您可以实现自己的功能:

CREATE EXTENSION unaccent;

CREATE OR REPLACE FUNCTION lower_unaccent(input text)
 RETURNS text
 LANGUAGE plpgsql
AS $function$
BEGIN
    return lower(unaccent(input));
END;
$function$;

电话就到了

select lower_unaccent('Hôtel')
>> 'hotel'

3
投票

经过测试的方法是使用

~*

如下例

SELECT id FROM groups WHERE name ~* 'administrator'

1
投票

对于不区分大小写的参数化查询,您可以使用以下语法:

 "select * from article where upper(content) LIKE upper('%' || $1 || '%')"

1
投票
-- Install 'Case Ignore Test Extension'
create extension citext;

-- Make a request
select 'Thomas'::citext in ('thomas', 'tiago');

select name from users where name::citext in ('thomas', 'tiago');

0
投票

对于超出这个简单范围的复杂查询

field = value
我建议您使用不区分大小写的不确定性排序规则并将其应用于您的查询

CREATE COLLATION case_insensitive (provider = icu, locale = 'und-u-ks-level2', deterministic = false);

然后使用它

SELECT id FROM groups where name='administrator' COLLATE case_insensitive;

查看完整文档 https://www.postgresql.org/docs/current/collation.html#COLLATION-NONDETERMINISTIC


-20
投票
select id from groups where name in ('administrator', 'ADMINISTRATOR', 'Administrator')
© www.soinside.com 2019 - 2024. All rights reserved.