postgresで重複する配列値を排除する


87

タイプの配列がありbigintますが、その配列の重複する値を削除するにはどうすればよいですか?

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

私は得る必要があります array[1234, 5343, 6353, ...]

SELECT uniq(sort('{1,2,3,2,1}'::int[]))postgresマニュアルで例をテストしましたが、機能していません。

回答:


94

私も同じように直面しました。しかし、私の場合の配列はarray_agg関数を介して作成されます。そして幸いなことに、次のようなDISTINCT値を集約できます

  array_agg(DISTINCT value)

これは私にとってはうまくいきます。


5
DISTINCTはウィンドウ関数ではサポートされていないことに注意してください。
考えられる2016年

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 2017

@ user48956、あなたが値として配列を入力すると、クエリでごとにグループ化された値として単一の列を設定する必要があり、論理的であること
ダニエル・チューリップ

83

sort(int[])そしてuniq(int[])関数はによって提供されるintarrayのcontribモジュール。

使用できるようにするには、モジュールをインストールする必要があります

intarray contribモジュールを使用したくない場合、または異なるタイプの配列から重複を削除する必要がある場合は、他に2つの方法があります。

少なくともPostgreSQL8.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ユーティリティ標準ライブラリ(?)はどこにありますか?

検索してみてください...いくつかの標準を参照してください。

  • postgres.cz/wiki/Array_based_functions:良いリファレンスです!

  • JDBurnZ / postgresql-anyarray、優れたイニシアチブですが、強化するにはいくつかのコラボレーションが必要です。

  • wiki.postgresql.org/Snippets、欲求不満のイニシアチブ、しかし「公式ウィキ」は、強化するためにいくつかのコラボレーションが必要です。

  • MADlib:いいね!....しかし、それは象であり、「純粋なSQLスニペットライブラリ」ではありません。


最もシンプルで高速なarray_distinct()スニペット-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]"}"

編集:より複雑ですが便利な「ドロップヌル」パラメータ

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;

FROM unnest($ 1)t(x)でt(x)が何をしているのか説明していただけますか...また、挿入されたアイテムの順序を維持するにはどうすればよいですか
abhirathore2006 2016年

@ abhirathore2006この回答はWikiであり、提案した説明を書くことができます。「順序を維持する」については、いいえ、これは破壊的な解決策です。元の配列の順序を維持するには、このページのPLpgSQLソリューションを参照してください。それはまた、ソート区別の2つの要件の共通点ですここでの主な回答の成功とそこにある私のコメントを参照してください)。
ピータークラウス

心配ありません、私はすでにどこかから解決策を見つけました、はい、それはplsqlソリューションです
abhirathore2006 2016年

13

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]


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)
Peter Krauss


3

まだpostgres8.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}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.