wyeliminować zduplikowane wartości tablic w postgres

86

Mam tablicę typu bigint, jak mogę usunąć zduplikowane wartości w tej tablicy?

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

Powinienem dostać array[1234, 5343, 6353, ...]

Przetestowałem przykład SELECT uniq(sort('{1,2,3,2,1}'::int[]))w podręczniku postgres, ale nie działa.

GVK
źródło

Odpowiedzi:

92

Zmierzyłem się z tym samym. Ale tablica w moim przypadku jest tworzona za pomocą array_aggfunkcji. I na szczęście pozwala na agregację wartości DISTINCT , takich jak:

  array_agg(DISTINCT value)

To działa dla mnie.

Michaił Lisakow
źródło
5
Zauważ, że DISTINCT nie jest obsługiwany przez funkcje okna.
pomyślenia
tks guytrim(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]) daje „{{1,2,2,3}}”
user48956
@ user48956, czyli logiczne, ponieważ wprowadzasz tablicę jako wartość, musisz ustawić pojedynczą kolumnę jako wartość, która jest pogrupowana według zapytania
Daniël Tulp
83

sort(int[])I uniq(int[])funkcje są dostarczane przez intarray modułu contrib.

Aby móc z niego korzystać należy zainstalować moduł .

Jeśli nie chcesz używać modułu wstawiania intarray lub jeśli musisz usunąć duplikaty z tablic innego typu, masz dwa inne sposoby.

Jeśli masz przynajmniej PostgreSQL 8.4, możesz skorzystać z unnest(anyarray)funkcji

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

Alternatywnie możesz stworzyć własną funkcję, aby to zrobić

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

Oto przykładowe wywołanie:

SELECT array_sort_unique('{1,2,3,2,1}'::int[]);
 array_sort_unique 
-------------------
 {1,2,3}
(1 row)
mnencia
źródło
1
Rozwiązanie problemu („wyeliminuj zduplikowane wartości tablicy”) nie wymaga sortowania . Chociaż zazwyczaj jest to użyteczna funkcja, jest niepotrzebna (koszt procesora) w tym kontekście / wymaganiu.
Peter Krauss,
27

... Gdzie biblioteki statandard (?) Dla tego rodzaju narzędzia array_X ?

Spróbuj wyszukać ... Zobacz niektóre, ale bez standardu:


Najprostsza i szybsza array_distinct()funkcja snippet-lib

Tutaj najprostsza i być może szybsza implementacja dla array_unique()lub 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;

UWAGA: działa zgodnie z oczekiwaniami z każdym typem danych, z wyjątkiem tablicy tablic,

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

„efektem ubocznym” jest rozbicie wszystkich tablic w zestawie elementów.

PS: z tablicami JSONB działa dobrze,

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

Edycja: bardziej złożona, ale użyteczna, parametr „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;
Peter Krauss
źródło
czy możesz wyjaśnić, co robi t (x) w FROM unnest (1 $) t (x) ... także jak mogę zachować kolejność elementów, w których zostały wstawione
abhirathore2006
@ abhirathore2006 ta odpowiedź to Wiki, możesz wpisać zasugerowane wyjaśnienia. O "zachowaj porządek", nie, jest to destrukcyjne rozwiązanie. Zobacz rozwiązania PLpgSQL na tej stronie, aby zachować oryginalną kolejność tablic. Jest to również wspólne dla dwóch wymagań, uporządkowanych i odrębnych (patrz sukces głównej odpowiedzi tutaj i mój komentarz tam).
Peter Krauss,
nie martw się, już znalazłem rozwiązanie z innego miejsca, tak, to jest rozwiązanie plsql
abhirathore2006
13

Zebrałem zestaw procedur składowanych (funkcji) w celu zwalczania braku obsługi tablic przez PostgreSQL anyarray. Te funkcje są zaprojektowane do działania z dowolnym typem danych tablicy, a nie tylko liczbami całkowitymi, jak robi to intarray: https://www.github.com/JDBurnZ/anyarray

W twoim przypadku wszystko, czego naprawdę potrzebujesz, to anyarray_uniq.sql. Skopiuj i wklej zawartość tego pliku do zapytania PostgreSQL i wykonaj je, aby dodać funkcję. Jeśli potrzebujesz również sortowania tablic, dodaj także anyarray_sort.sql.

Stamtąd możesz wykonać proste zapytanie w następujący sposób:

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

Zwraca coś podobnego do: ARRAY[1234, 6353, 5343]

Lub jeśli potrzebujesz sortowania:

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

Zwróć dokładnie: ARRAY[1234, 5343, 6353]

Joshua Burns
źródło
13

Użycie DISTINCTniejawnie sortuje tablicę. Jeśli podczas usuwania duplikatów trzeba zachować względną kolejność elementów tablicy, funkcja może zostać zaprojektowana w następujący sposób: (powinna działać od 9.4 wzwyż)

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;
tbussmann
źródło
1
najlepsza odpowiedź! zobacz też: dba.stackexchange.com/questions/211501/…
fjsj
9

Oto sposób „wbudowany”:

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;

Najpierw tworzymy zestaw z tablicy, następnie wybieramy tylko odrębne wpisy, a następnie agregujemy go z powrotem w tablicę.

alexkovelsky
źródło
9
Albo "more inline" ;-) SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
Peter Krauss
4

W jednym zapytaniu zrobiłem to:

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

Gregorio Freidin
źródło
3

Dla ludzi takich jak ja, którzy nadal mają do czynienia z postgres 8.2, ta rekurencyjna funkcja może wyeliminować duplikaty bez zmiany sortowania tablicy

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;

na przykład :

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

da

{3,8,2,6,4,1,99}
bayonatof
źródło