23

我在这里、谷歌或文档中找不到答案……
我需要对数组类型进行不区分大小写的选择。

因此,如果:

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

我需要

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

匹配。

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

ILIKE而不是=似乎工作,但我一直很紧张LIKE- 这是最好的方法吗?

4

6 回答 6

20

这对我来说似乎很骇人听闻,但我认为它应该有效

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 索引。

于 2013-05-01T01:28:56.563 回答
20

未提及的一种替代方法是安装PostgreSQL 8.4+ 附带citext扩展并使用以下数组citext

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

如果您想对此严格正确并避免扩展,则必须执行一些非常丑陋的子查询,因为 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);
于 2013-05-01T01:50:17.457 回答
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;

If array elements are unique within arrays in lower case, you don't even need the GROUP BY, since every value can only match once.

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

'foo' must be lower case, obviously.
Should be fast.

If you want that fast wit a big table, I would create a functional GIN index, though.

于 2013-05-01T02:40:50.690 回答
0

my solution to exclude values using a sub select...

and groupname not ilike all (
    select unnest(array[exceptionname||'%'])
    from public.group_exceptions
    where ...
      and ...
      )
于 2017-03-23T13:03:45.517 回答
0

Regular expression may do the job for most cases

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

于 2019-07-22T06:40:54.717 回答
0

I find creating a custom PostgreSQL function works best for me

CREATE OR REPLACE FUNCTION lower(text_array text[]) RETURNS text[] AS
    $BODY$
         SELECT (lower(text_array::text))::text[] 
    $BODY$
LANGUAGE SQL IMMUTABLE;
于 2020-09-07T11:56:37.210 回答