将数组与多维数组的元素进行比较

时间:2018-01-19 15:27:53

标签: sql arrays postgresql multidimensional-array

我在PostgreSQL 9.6数据库中有一个表:

CREATE TABLE new_table (
 column_name varchar(255)[],
 name        varchar(40)
);

INSERT INTO new_table VALUES
 ('{one, two}'  , 'first_user'),
 ('{other, two}', 'second_user'),
 ('{one, more}' , 'third_user');

我有一个数组数组(2D数组),并希望找到表column_name匹配任何包含的1D数组的表的所有行。我喜欢这样的事情:

select * 
from new_table as s
where s.column_name = any('{{"one", "two"}, {"one", "more"}, {"two", "five"}}')

但这给了我错误:

ERROR:  could not find array type for data type text[]

我想要的结果:

column_name |    name
------------+--------------
{one,two}   | first_user
{one,more}  | third_user

任何人都有任何想法?

2 个答案:

答案 0 :(得分:0)

使用数组运算符与运算符一起工作:

t=# select *
from new_table as s
where s.column_name <@ '{{"one", "two"}, {"one", "more"}, {"two", "five"}}';
 column_name |    name
-------------+------------
 {one,two}   | first_user
 {one,more}  | third_user
(2 rows)

我认为https://www.postgresql.org/docs/current/static/functions-comparisons.html#idm46428706346880可能有一些注释,表达式不是数组,您无法将其用于此类比较

<强>更新

能够通过1维排除&#34;排除数组&#34;并使用in comarison的结果集,使用Pavel Stěhule建议的function

t=# select * from new_table 
where column_name in (
  select reduce_dim('{{one, two}, {two, more}, {one, five}}'::character varying[])
);
 column_name |    name
-------------+------------
 {one,two}   | first_user
(1 row)

答案 1 :(得分:0)

错误消息

为了记录,你的表面错误:

ERROR:  could not find array type for data type text[]

..将通过明确的演员而消失。像:

...
WHERE column_name = any('{{"one", "two"}, {"one", "more"}, {"two", "five"}}'::varchar[])

但那解决了潜在的问题:

ERROR:  operator does not exist: character varying[] = character varying

解释

Postgres对多维数组的支持可能令人困惑。实际上,varchar(255)[]在内部解析为与varchar(255)[][]完全相同的数据类型。

每个数组值的 元素 类型为varchar(不是varchar[])。 ANY构造有效地忽略了数组维度。 The manual:

  

数组比较逐个元素地比较数组内容

解决方案

要实现您的目标,您需要将2D阵列替换为1D阵列。每个数据库创建此函数一次

CREATE OR REPLACE FUNCTION unnest_2d_1d(ANYARRAY, OUT a ANYARRAY)
  RETURNS SETOF ANYARRAY AS
$func$
BEGIN
   FOREACH a SLICE 1 IN ARRAY $1 LOOP
      RETURN NEXT;
   END LOOP;
END
$func$  LANGUAGE plpgsql IMMUTABLE STRICT;

进一步阅读:

现在,所有这些查询都有效:

SELECT t.*
FROM   unnest_2d_1d('{{"one", "two"}, {"one", "more"}, {"two", "five"}}'::varchar[]) a(column_name)
JOIN   new_table t USING (column_name);

或者:

SELECT t.*
FROM   new_table t
WHERE  column_name = ANY ((SELECT unnest_2d_1d('{{"one", "two"}, {"one", "more"}, {"two", "five"}}'::varchar[])));

或者:

...
WHERE  column_name IN ((SELECT unnest_2d_1d('{{"one", "two"}, {"one", "more"}, {"two", "five"}}'::varchar[])));

dbfiddle here

相关:

旁白

这是极少数情况下,数组列上的btree索引可能有用:

CREATE INDEX ON new_table(column_name);

Postgres中varchar(255)没有什么特别之处。我大多只使用text。参见: