在postgres中消除重复的数组值


86

我有一个类型的数组bigint,如何删除该数组中的重复值?

例如: array[1234, 5343, 6353, 1234, 1234]

我应该得到 array[1234, 5343, 6353, ...]

SELECT uniq(sort('{1,2,3,2,1}'::int[]))在postgres手册中测试了该示例,但是它不起作用。

Answers:


92

我面临着同样的事情。但是在我的情况下,数组是通过array_agg函数创建的。幸运的是,它允许聚合DISTINCT值,例如:

  array_agg(DISTINCT value)

这对我有用。


5
请注意,窗口功能不支持DISTINCT。
令人难以置信的

TKS家伙trim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
法比奥Zangirolami

4
select array_agg(DISTINCT Array [1,2,2,3])给出“ {{1,2,2,3}}”
user48956

@ user48956,即逻辑,当你进入数组作为值,需要设置一个单一的列值,该值是通过在查询分组
丹尼尔TULP

83

sort(int[])uniq(int[])功能是由提供intarray的contrib模块。

要启用它,必须安装模块

如果您不想使用intarray contrib模块,或者必须从不同类型的数组中删除重复项,则可以使用另外两种方法。

如果您至少拥有PostgreSQL 8.4,则可以利用unnest(anyarray)功能

SELECT ARRAY(SELECT DISTINCT UNNEST('{1,2,3,2,1}'::int[]) ORDER BY 1);
 ?column? 
----------
 {1,2,3}
(1 row)

或者,您可以创建自己的函数来执行此操作

CREATE OR REPLACE FUNCTION array_sort_unique (ANYARRAY) RETURNS ANYARRAY
LANGUAGE SQL
AS $body$
  SELECT ARRAY(
    SELECT DISTINCT $1[s.i]
    FROM generate_series(array_lower($1,1), array_upper($1,1)) AS s(i)
    ORDER BY 1
  );
$body$;

这是一个示例调用:

SELECT array_sort_unique('{1,2,3,2,1}'::int[]);
 array_sort_unique 
-------------------
 {1,2,3}
(1 row)

1
问题的解决方案(“消除重复的数组值”)不需要进行排序。尽管通常是有用的功能,但在此上下文/要求中这是不必要的(CPU成本)。
彼得·克劳斯

27

...哪里有这种array_X实用程序statandard(?)?

尝试搜索...看到一些但没有标准:


最简单,最快的array_distinct()代码片段库功能

这里是array_unique()或的最简单,也许是更快的实现array_distinct()

CREATE FUNCTION array_distinct(anyarray) RETURNS anyarray AS $f$
  SELECT array_agg(DISTINCT x) FROM unnest($1) t(x);
$f$ LANGUAGE SQL IMMUTABLE;

注意:它适用于任何数据类型,但数组数组除外,

SELECT  array_distinct( array[3,3,8,2,6,6,2,3,4,1,1,6,2,2,3,99] ), 
        array_distinct( array['3','3','hello','hello','bye'] ), 
        array_distinct( array[array[3,3],array[3,3],array[3,3],array[5,6]] );
 -- "{1,2,3,4,6,8,99}",  "{3,bye,hello}",  "{3,5,6}"

“副作用”是爆炸一组元素中的所有数组。

PS:使用JSONB数组效果很好,

SELECT array_distinct( array['[3,3]'::JSONB, '[3,3]'::JSONB, '[5,6]'::JSONB] );
 -- "{"[3, 3]","[5, 6]"}"

编辑:更复杂但有用,一个“ drop nulls”参数

CREATE FUNCTION array_distinct(
      anyarray, -- input array 
      boolean DEFAULT false -- flag to ignore nulls
) RETURNS anyarray AS $f$
      SELECT array_agg(DISTINCT x) 
      FROM unnest($1) t(x) 
      WHERE CASE WHEN $2 THEN x IS NOT NULL ELSE true END;
$f$ LANGUAGE SQL IMMUTABLE;

您能解释一下t(x)在unnest($ 1)t(x)中的作用吗?还如何保持插入项的顺序
abhirathore2006 16-10-18

@ abhirathore2006这个答案是一个Wiki,您可以编写您提出的解释。关于“保持顺序”,不,这是一个破坏性的解决方案,请参阅本页中的PLpgSQL解决方案以保留原始数组的顺序。这也是对两个要求的要求,即排序区分(请参见此处主要回答的成功和此处的评论)。
彼得·克劳斯

不用担心,我已经从其他地方找到了解决方案,是的,这是plsql解决方案
abhirathore2006 16-10-19

13

我已经组装了一组存储过程(函数),以解决PostgreSQL缺少coind的数组处理问题anyarray。这些函数旨在跨任何数组数据类型工作,而不仅仅是像intarray这样的整数:https://www.github.com/JDBurnZ/anyarray

就您而言,您真正需要的是anyarray_uniq.sql。复制该文件的内容并将其粘贴到PostgreSQL查询中,然后执行以添加该函数。如果还需要数组排序,请添加anyarray_sort.sql

从那里,您可以执行一个简单的查询,如下所示:

SELECT ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234])

返回类似于以下内容的内容: ARRAY[1234, 6353, 5343]

或者,如果您需要排序:

SELECT ANYARRAY_SORT(ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234]))

准确返回: ARRAY[1234, 5343, 6353]


13

使用DISTINCT隐式对数组进行排序。如果在删除重复项时需要保留数组元素的相对顺序,则可以将函数设计如下:(应从9.4开始工作)

CREATE OR REPLACE FUNCTION array_uniq_stable(anyarray) RETURNS anyarray AS
$body$
SELECT
    array_agg(distinct_value ORDER BY first_index)
FROM 
    (SELECT
        value AS distinct_value, 
        min(index) AS first_index 
    FROM 
        unnest($1) WITH ORDINALITY AS input(value, index)
    GROUP BY
        value
    ) AS unique_input
;
$body$
LANGUAGE 'sql' IMMUTABLE STRICT;

1
最佳答案!另请参见:dba.stackexchange.com/questions/211501/…–
fjsj,

9

这是“内联”方式:

SELECT 1 AS anycolumn, (
  SELECT array_agg(c1)
  FROM (
    SELECT DISTINCT c1
    FROM (
      SELECT unnest(ARRAY[1234,5343,6353,1234,1234]) AS c1
    ) AS t1
  ) AS t2
) AS the_array;

首先,我们从数组创建一个集合,然后仅选择不同的条目,然后将其聚合回数组。


9
或“更多内联” ;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
彼得·克劳斯

4

在一个查询中,我这样做:

SELECT (select array_agg(distinct val) from ( select unnest(:array_column) as val ) as u ) FROM :your_table;


3

对于像我这样仍然需要处理postgres 8.2的人,此递归函数可以消除重复项,而无需更改数组的排序

CREATE OR REPLACE FUNCTION my_array_uniq(bigint[])
  RETURNS bigint[] AS
$BODY$
DECLARE
    n integer;
BEGIN

    -- number of elements in the array
    n = replace(split_part(array_dims($1),':',2),']','')::int;

    IF n > 1 THEN
        -- test if the last item belongs to the rest of the array
        IF ($1)[1:n-1] @> ($1)[n:n] THEN
            -- returns the result of the same function on the rest of the array
            return my_array_uniq($1[1:n-1]);
        ELSE
            -- returns the result of the same function on the rest of the array plus the last element               
            return my_array_uniq($1[1:n-1]) || $1[n:n];
        END IF;
    ELSE
        -- if array has only one item, returns the array
        return $1;
    END IF;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

举个例子 :

select my_array_uniq(array[3,3,8,2,6,6,2,3,4,1,1,6,2,2,3,99]);

会给

{3,8,2,6,4,1,99}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.