PostgreSQL中两个数组的联合,没有取消

时间:2014-06-10 18:05:32

标签: arrays postgresql union plpgsql

我在PostgreSQL中有两个我需要联合的数组。例如:

{1,2,3} union {1,4,5}将返回{1,2,3,4,5}

使用连接(||)运算符不会删除重复的条目,即返回{1,2,3,1,4,5}

我在网上找到了一个解决方案,但是我不喜欢它需要如何取消这两个数组: select ARRAY(select unnest(ARRAY[1,2,3]) as a UNION select unnest(ARRAY[2,3,4,5]) as a)

是否有一个运算符或内置函数可以干净地结合两个数组?

4 个答案:

答案 0 :(得分:17)

如果您的问题是不需要两次,那么只需要一次

select array_agg(a order by a)
from (
    select distinct unnest(array[1,2,3] || array[2,3,4,5]) as a
) s;

答案 1 :(得分:10)

扩展intarray(在contrib包中)包含一些有用的函数和运算符:

postgres=# create extension intarray ;
CREATE EXTENSION

使用单管道操作员:

postgres=# select array[1,2,3] | array[3,4,5];
  ?column?   
─────────────
 {1,2,3,4,5}
(1 row)

uniq函数:

postgres=# select uniq(ARRAY[1,2,3] || ARRAY[3,4,5]);
    uniq     
─────────────
 {1,2,3,4,5}
(1 row)

ANSI / SQL知道一个多集,但PostgreSQL还不支持它。

答案 2 :(得分:2)

可以这样做......

select uniq(sort(array_remove(array_cat(ARRAY[1,2,3], ARRAY[1,4,5]), NULL)))

给出:

{1,2,3,4,5}

需要array_remove,因为您无法使用NULLS对数组进行排序。 需要排序,因为uniq仅在找到相邻元素时才重复删除。

这种方法相对于@Clodoaldo Neto的好处是,它在整个选择范围内起作用,并且不在FROM子句中排除。这使得在同一时间在单个表扫描中同时操作多个阵列列变得简单。 (虽然在评论中看到Ryan Guill版本的功能)。

此外,此模式适用于所有数组类型(谁的元素可排序)。

缺点是,可行的是,对于较长的数组,它的速度会慢一些(由于排序和3个中间数组分配)。

如果你想在结果中保留NULL,我认为这个和接受答案都会失败。

答案 3 :(得分:0)

当您尝试从行的 group 中获取数组值列的集合并集时,基于intarray的答案不起作用。可以将接受的基于array_agg的答案 修改为有效,例如

SELECT selector_column, array_agg(a ORDER BY a) AS array_valued_column
FROM (
    SELECT DISTINCT selector_column, UNNEST(array_valued_column) AS a FROM table
) _ GROUP BY selector_column;

但是,如果将其深埋在复杂的查询中,则计划程序将无法将外部WHERE表达式传递过去,即使它们将大大减少必须处理的行数。在这种情况下,正确的解决方案是定义自定义聚合:

CREATE FUNCTION array_union_step (s ANYARRAY, n ANYARRAY) RETURNS ANYARRAY
   AS $$ SELECT s || n; $$
   LANGUAGE SQL IMMUTABLE LEAKPROOF PARALLEL SAFE;

CREATE FUNCTION array_union_final (s ANYARRAY) RETURNS ANYARRAY
  AS $$
    SELECT array_agg(i ORDER BY i) FROM (
      SELECT DISTINCT UNNEST(x) AS i FROM (VALUES(s)) AS v(x)
    ) AS w WHERE i IS NOT NULL;
  $$
  LANGUAGE SQL IMMUTABLE LEAKPROOF PARALLEL SAFE;

CREATE AGGREGATE array_union (ANYARRAY) (
  SFUNC = array_union_step,
  STYPE = ANYARRAY,
  FINALFUNC = array_union_final,
  INITCOND = '{}',
  PARALLEL = SAFE
);

用法是

SELECT selector_column, array_union(array_valued_column) AS array_valued_column
  FROM table
  GROUP BY selector_column;

它在“内部”执行相同的操作,但是由于它被打包到一个聚合函数中,因此计划者可以看到它。

有可能通过让step函数执行UNNEST并将行附加到临时表(而不是临时数组)上来提高效率,但是我不知道该怎么做,这已经足够了我的用例。