PostgreSQL对数组不敏感的SELECT

时间:2013-05-01 00:58:49

标签: sql postgresql pattern-matching case-insensitive

我在谷歌或文档中找到答案时遇到了问题...... 我需要针对数组类型进行不区分大小写的选择。

所以如果:

value = {"Foo","bar","bAz"}

我需要

SELECT value FROM table WHERE 'foo' = ANY(value)

匹配。

我尝试了很多lower()的组合而没有成功。

ILIKE代替=似乎有效,但我一直对LIKE感到紧张 - 这是最好的方法吗?

6 个答案:

答案 0 :(得分:17)

未提及的一个替代方法是安装PostgreSQL 8.4+附带的the citext extension并使用citext数组:

regress=# CREATE EXTENSION citext;
regress=# SELECT 'foo' = ANY( '{"Foo","bar","bAz"}'::citext[] );
 ?column? 
----------
 t
(1 row)

如果你想严格正确并避免扩展,你必须做一些pretty ugly subqueries,因为Pg没有很多丰富的数组操作,特别是没有功能映射操作。类似的东西:

SELECT array_agg(lower(($1)[n])) FROM generate_subscripts($1,1) n;

...其中$ 1是数组参数。在你的情况下,我认为你可以作弊,因为你不关心保留数组的顺序,所以你可以这样做:

SELECT 'foo' IN (SELECT lower(x) FROM unnest('{"Foo","bar","bAz"}'::text[]) x);

答案 1 :(得分:16)

这对我来说似乎很苛刻,但我认为它应该有用

SELECT value FROM table WHERE 'foo' = ANY(lower(value::text)::text[])
如果您的数组可以有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;
$$;

然后你可以这样做:

SELECT value FROM table WHERE 'foo' = ANY(lower(value));

这实际上可能是最好的方法。如果需要,您还可以在函数的输出上创建GIN索引。

答案 2 :(得分:4)

另一种选择是使用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;

我添加了一个id列,以便完全相同的结果 - 例如,如果基表中有重复项,则重复value。根据您的具体情况,您可以省略查询中的id以折叠结果中的重复项,或者如果没有开头的重复项。还演示了一种语法替代方法:

SELECT value
FROM  (SELECT value, lower(unnest(value)) AS val FROM tbl) x
WHERE  val = 'foo'
GROUP  BY value;

如果数组元素在小写的数组中是唯一的,那么您甚至不需要GROUP BY,因为每个value只能匹配一次。

SELECT value
FROM  (SELECT value, lower(unnest(value)) AS val FROM tbl) x
WHERE  val = 'foo';
显然,

'foo'必须是小写的 应

如果你希望 fast 有一个大表,我会创建一个功能GIN索引

答案 3 :(得分:0)

我的解决方案是使用子选择...

排除值
and groupname not ilike all (
    select unnest(array[exceptionname||'%'])
    from public.group_exceptions
    where ...
      and ...
      )

答案 4 :(得分:0)

在大多数情况下,正则表达式可以胜任

SELECT array_to_string('{“ a”,“ b”,“ c”}':: text [],'|')〜* ANY('{“ A”,“ B”,“ C”}' );

答案 5 :(得分:0)

我发现创建自定义PostgreSQL函数最适合我

CREATE OR REPLACE FUNCTION lower(text_array text[]) RETURNS text[] AS
    $BODY$
         SELECT (lower(text_array::text))::text[] 
    $BODY$
LANGUAGE SQL IMMUTABLE;