postgres'te yinelenen dizi değerlerini eleyin


87

Bir dizi türüm var bigint, bu dizideki yinelenen değerleri nasıl kaldırabilirim?

Ör: array[1234, 5343, 6353, 1234, 1234]

almalıyım array[1234, 5343, 6353, ...]

SELECT uniq(sort('{1,2,3,2,1}'::int[]))Postgres kılavuzundaki örneği test ettim ama çalışmıyor.

Yanıtlar:


94

Ben de aynı şekilde yüzleştim. Ancak benim durumumda bir dizi array_aggişlev aracılığıyla oluşturulur . Ve neyse ki DISTINCT değerlerinin toplanmasına izin verir , örneğin:

  array_agg(DISTINCT value)

Bu benim için çalışıyor.


5
DISTINCT'in pencere işlevleri için desteklenmediğini unutmayın.
Düşünülebilir

tks adamtrim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
Fábio Zangirolami

4
select array_agg (DISTINCT Array [1,2,2,3]) "{{1,2,2,3}}" değerini verir
user48956

@ user48956, bu mantıklıdır, değer olarak bir dizi girdiğinizde, sorguda gruplanan değer olarak tek bir sütun ayarlamanız gerekir
Daniël Tulp

83

sort(int[])Ve uniq(int[])işlevleri tarafından sağlanan intarray contrib modülü.

Kullanımını etkinleştirmek için modülü kurmanız gerekir .

İntarray katkı modülünü kullanmak istemiyorsanız veya farklı türdeki dizilerden kopyaları kaldırmanız gerekiyorsa, iki yolunuz daha vardır.

En azından PostgreSQL 8.4'e sahipseniz, unnest(anyarray)fonksiyondan yararlanabilirsiniz.

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

Alternatif olarak, bunu yapmak için kendi işlevinizi oluşturabilirsiniz

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$;

İşte örnek bir çağrı:

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

1
Sorunun çözümünün ("yinelenen dizi değerlerini eleyin") sıralanması gerekmez . Genellikle kullanışlı bir özellik olmasına rağmen, bu bağlamda / gereksinimde gereksizdir (CPU maliyeti).
Peter Krauss

27

... Bu tür dizi_X yardımcı programı için standart kitaplıkların (?) Nerede ?

Aramayı deneyin ... Bazılarını görün ama standart yok:


En basit ve daha hızlı array_distinct()snippet-lib işlevi

İçin en basit ve belki de daha hızlı uygulanmasını Buraya array_unique()ya 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;

NOT: dizi dizisi dışında herhangi bir veri türü ile beklendiği gibi çalışır,

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}"

"yan etki", bir elemanlar kümesindeki tüm dizileri patlatmaktır.

Not: JSONB dizileri ile iyi çalışıyor,

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

Düzenleme: daha karmaşık ama kullanışlı bir "drop nulls" parametresi

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) 'in yuvasız (1 $) t (x)' de ne yaptığını açıklar mısınız ... ayrıca
ekledikleri

@ abhirathore2006 bu cevap bir Wiki'dir, önerdiğiniz açıklamaları yazabilirsiniz. "Sırayı koru" hakkında, hayır, yıkıcı bir çözümdür, Orijinal dizi sırasını korumak için bu sayfadaki PLpgSQL çözümlerine bakın. Aynı zamanda, iki requiriments commom edilir sıralama ve farklı (ve sucess bakınız burada ana cevap ve benim yorumunu orada).
Peter Krauss

Endişelenme, çözümü zaten başka bir yerden buldum, evet bu plsql çözümü
abhirathore2006

13

PostgreSQL'in dizi işleme eksikliğiyle mücadele etmek için bir dizi saklı yordamı (işlevleri) bir araya getirdim anyarray. Bu işlevler, yalnızca intarray'in yaptığı gibi tamsayılar değil, herhangi bir dizi veri türünde çalışmak üzere tasarlanmıştır: https://www.github.com/JDBurnZ/anyarray

Senin durumunda, gerçekten ihtiyacın olan tek şey anyarray_uniq.sql. Bu dosyanın içeriğini bir PostgreSQL sorgusuna kopyalayıp yapıştırın ve işlevi eklemek için çalıştırın. Dizi sıralamasına da ihtiyacınız varsa, ekleyin anyarray_sort.sql.

Oradan, aşağıdaki gibi basit bir sorgu oluşturabilirsiniz:

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

Şuna benzer bir şey döndürür: ARRAY[1234, 6353, 5343]

Veya sıralamanız gerekiyorsa:

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

Tam olarak dön: ARRAY[1234, 5343, 6353]


13

Kullanmak DISTINCTdiziyi örtük olarak sıralar. Eğer göreli sırası dizi elemanlarının çiftleri kaldırılırken, fonksiyon aşağıdaki gibi dizayn edilebilir korunması gereken: (itibaren 9.4 çalışması gerekir)

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
en iyi cevap! ayrıca bkz: dba.stackexchange.com/questions/211501/…
fjsj

9

İşte "satır içi" yol:

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;

Önce diziden bir küme oluştururuz, sonra sadece farklı girdileri seçeriz ve sonra onu tekrar dizi halinde toparız.


9
Veya "daha satır içi" ;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
Peter Krauss

4

Tek bir sorguda şunu yaptım:

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


3

Hala postgres 8.2 ile uğraşmak zorunda olan benim gibi insanlar için, bu özyinelemeli işlev dizinin sıralamasını değiştirmeden kopyaları ortadan kaldırabilir.

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;

Örneğin :

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

verecek

{3,8,2,6,4,1,99}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.