Per*_*ryW 20 sql postgresql case-insensitive pattern-matching
我在谷歌或文档中找到答案时遇到问题......
我需要针对数组类型做一个不区分大小写的选择.
因此,如果:
value = {"Foo","bar","bAz"}
Run Code Online (Sandbox Code Playgroud)
我需要
SELECT value FROM table WHERE 'foo' = ANY(value)
Run Code Online (Sandbox Code Playgroud)
匹配.
我尝试了很多lower()的组合而没有成功.
ILIKE
而不是=
似乎工作,但我一直很紧张LIKE
- 这是最好的方式吗?
Cra*_*ger 18
一个未提及的替代方法是安装PostgreSQL 8.4+附带的citext
扩展并使用以下数组citext
:
regress=# CREATE EXTENSION citext;
regress=# SELECT 'foo' = ANY( '{"Foo","bar","bAz"}'::citext[] );
?column?
----------
t
(1 row)
Run Code Online (Sandbox Code Playgroud)
如果你想对此严格正确并避免扩展,你必须做一些相当丑陋的子查询,因为Pg没有很多丰富的数组操作,特别是没有功能映射操作.就像是:
SELECT array_agg(lower(($1)[n])) FROM generate_subscripts($1,1) n;
Run Code Online (Sandbox Code Playgroud)
...其中$ 1是数组参数.在你的情况下,我认为你可以作弊,因为你不关心保留数组的顺序,所以你可以这样做:
SELECT 'foo' IN (SELECT lower(x) FROM unnest('{"Foo","bar","bAz"}'::text[]) x);
Run Code Online (Sandbox Code Playgroud)
Chr*_*ers 17
这对我来说似乎很苛刻,但我认为它应该有效
SELECT value FROM table WHERE 'foo' = ANY(lower(value::text)::text[])
Run Code Online (Sandbox Code Playgroud)
ilike
如果您的阵列可以有_
或有问题可能会有问题%
请注意,您正在做的是将文本数组转换为单个文本字符串,将其转换为小写,然后再转换回数组.这应该是安全的.如果这还不够,你可以使用string_to_array和array_to_string的各种组合,但我认为标准的文本表示应该更安全.
更新下面的子查询解决方案,一个选项是一个简单的功能:
CREATE OR REPLACE FUNCTION lower(text[]) RETURNS text[] LANGUAGE SQL IMMUTABLE AS
$$
SELECT array_agg(lower(value)) FROM unnest($1) value;
$$;
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
SELECT value FROM table WHERE 'foo' = ANY(lower(value));
Run Code Online (Sandbox Code Playgroud)
这实际上可能是最好的方法.如果需要,您还可以在函数的输出上创建GIN索引.
另一种选择是unnest()
WITH tbl AS (SELECT 1 AS id, '{"Foo","bar","bAz"}'::text[] AS value)
SELECT value
FROM (SELECT id, value, unnest(value) AS val FROM tbl) x
WHERE lower(val) = 'foo'
GROUP BY id, value;
Run Code Online (Sandbox Code Playgroud)
我添加了一id
列以获得完全相同的结果 - 即value
如果基表中有重复项则重复。根据您的情况,您可以在查询中省略id
来折叠结果中的重复项,或者如果一开始就没有重复项。还演示了一种语法替代方案:
SELECT value
FROM (SELECT value, lower(unnest(value)) AS val FROM tbl) x
WHERE val = 'foo'
GROUP BY value;
Run Code Online (Sandbox Code Playgroud)
如果数组元素在小写数组中是唯一的,则甚至不需要GROUP BY
, 因为 everyvalue
只能匹配一次。
SELECT value
FROM (SELECT value, lower(unnest(value)) AS val FROM tbl) x
WHERE val = 'foo';
Run Code Online (Sandbox Code Playgroud)
'foo'
显然必须是小写。
应该很快。
如果你想要一个大表那么快,我会创建一个功能性的 GIN 索引。