有没有办法在 PostgreSQL 中编写不区分大小写的查询,例如我希望以下 3 个查询返回相同的结果。
SELECT id FROM groups where name='administrator'
SELECT id FROM groups where name='ADMINISTRATOR'
SELECT id FROM groups where name='Administrator'
使用
ILIKE
代替 LIKE
SELECT id FROM groups WHERE name ILIKE 'Administrator'
最常见的方法是将搜索字符串和数据小写或大写。但这有两个问题。
至少有三种不太常用的解决方案可能更有效。
CREATE INDEX ON groups (name::citext);
创建不区分大小写的索引。 (但请参阅下文。)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 之前,您需要阅读文档中的“字符串比较行为”和“限制”部分。
您可以使用
ILIKE
。即
SELECT id FROM groups where name ILIKE 'administrator'
您还可以阅读
ILIKE
关键字。它有时非常有用,尽管它不符合 SQL 标准。有关更多信息,请参阅此处:http://www.postgresql.org/docs/9.2/static/functions-matching.html
您还可以使用 POSIX 正则表达式,例如
SELECT id FROM groups where name ~* 'administrator'
SELECT 'asd' ~* 'AsD'
返回t
使用
ILIKE
select id from groups where name ILIKE 'adminstration';
如果你来的expressjs背景和名字是一个变量 使用
select id from groups where name ILIKE $1;
使用
~*
可以大大提高性能,具有INSTR的功能。
SELECT id FROM groups WHERE name ~* 'adm'
返回名称包含 OR 等于“adm”的行。
喜欢这种情况下的工作:
SELECT id
FROM groups
WHERE name ILIKE 'Administrator'
现有答案都不正确。
土耳其语有字母
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_compareusing 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
的唯一约束来消除不需要的重复项。
如果您不仅想要大写/小写还想要变音符号,您可以实现自己的功能:
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'
经过测试的方法是使用
~*
如下例
SELECT id FROM groups WHERE name ~* 'administrator'
对于不区分大小写的参数化查询,您可以使用以下语法:
"select * from article where upper(content) LIKE upper('%' || $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');
对于超出这个简单范围的复杂查询
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
select id from groups where name in ('administrator', 'ADMINISTRATOR', 'Administrator')