【问题标题】:eliminate duplicate array values in postgres消除 postgres 中的重复数组值
【发布时间】:2010-10-22 06:54:34
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: postgresql


    【解决方案1】:

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

      array_agg(DISTINCT value)
    

    这对我有用。

    【讨论】:

    • 请注意,窗口函数不支持 DISTINCT。
    • tks 家伙trim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
    • select array_agg(DISTINCT Array[1,2,2,3]) 给出“{{1,2,2,3}}”
    • @user48956,这是合乎逻辑的,当您输入一个数组作为值时,您需要将单个列设置为查询中分组的值
    【解决方案2】:

    sort(int[]) and uniq(int[]) functionsintarray contrib 模块提供。

    要启用它,您必须install the module

    如果您不想使用 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)
    

    【讨论】:

    • 问题的解决方案(“消除重复的数组值”)不需要排序。虽然通常是一个有用的功能,但在这种情况下/要求中它是不必要的(CPU 成本)。
    • 嗯,它实际上是需要的,uniq 只是“消除邻居重复”。保重!
    【解决方案3】:

    ... 这种array_X 实用程序标准 (?)在哪里??

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


    最简单快速的array_distinct()sn-p-lib函数

    这里是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) 在 FROM unnest($1) t(x) 中的作用...以及如何保持它们插入的项目的顺序
    • @abhirathore2006 这个答案是一个维基,你可以写下你建议的解释。关于“保持顺序”,不,这是一个破坏性的解决方案,请参阅此页面中的 PLpgSQL 解决方案以保留原始数组顺序。 sortdistinct 这两个要求也是通用的(参见main answer here 的成功和我的评论)。
    • 不用担心,我已经从其他地方找到了解决方案,是的,这就是 plsql 解决方案
    【解决方案4】:

    使用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;
    

    【讨论】:

    【解决方案5】:

    我已经组装了一组存储过程(函数)来解决 PostgreSQL 缺乏数组处理的问题 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]

    【讨论】:

      【解决方案6】:

      这是“内联”方式:

      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;
      

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

      【讨论】:

      • 或“更多内联”;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

        对于像我这样仍然要处理 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}
        

        【讨论】:

          猜你喜欢
          • 2010-11-12
          • 2019-04-08
          • 1970-01-01
          • 2015-06-24
          • 1970-01-01
          • 1970-01-01
          • 2021-08-26
          • 1970-01-01
          • 2019-10-19
          相关资源
          最近更新 更多