Eu tenho uma matriz do tipo bigint
, como posso remover os valores duplicados dessa matriz?
Ex: array[1234, 5343, 6353, 1234, 1234]
Eu deveria pegar array[1234, 5343, 6353, ...]
Testei o exemplo SELECT uniq(sort('{1,2,3,2,1}'::int[]))
no manual do postgres, mas não está funcionando.
postgresql
GVK
fonte
fonte
trim(string_agg(distinct to_char(z.dat_codigo,'0000000000'),'')) as dat_codigo,
As funções
sort(int[])
euniq(int[])
são fornecidas pelo módulo contrib intarray .Para habilitar seu uso, você deve instalar o módulo .
Se você não quiser usar o módulo de contribuição do intarray, ou se tiver que remover duplicatas de arrays de tipos diferentes, existem duas outras maneiras.
Se você tem pelo menos PostgreSQL 8.4 você pode tirar vantagem da
unnest(anyarray)
funçãoSELECT ARRAY(SELECT DISTINCT UNNEST('{1,2,3,2,1}'::int[]) ORDER BY 1); ?column? ---------- {1,2,3} (1 row)
Alternativamente, você pode criar sua própria função para fazer isso
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$;
Aqui está um exemplo de invocação:
SELECT array_sort_unique('{1,2,3,2,1}'::int[]); array_sort_unique ------------------- {1,2,3} (1 row)
fonte
... Onde estão as bibliotecas padrão (?) Para este tipo de utilitário array_X ??
Tente pesquisar ... Veja alguns, mas nenhum padrão:
postgres.cz/wiki/Array_based_functions : boa referência!
JDBurnZ / postgresql-anyarray , boa iniciativa, mas precisa de alguma colaboração para melhorar.
wiki.postgresql.org/Snippets , iniciativa frustrada, mas "wiki oficial", precisa de alguma colaboração para melhorar.
MADlib : bom! .... mas é um elefante, não uma "lib de snippets SQL pura".
array_distinct()
Função snippet-lib mais simples e rápidaAqui, a implementação mais simples e talvez mais rápida para
array_unique()
ouarray_distinct()
:CREATE FUNCTION array_distinct(anyarray) RETURNS anyarray AS $f$ SELECT array_agg(DISTINCT x) FROM unnest($1) t(x); $f$ LANGUAGE SQL IMMUTABLE;
NOTA: funciona como esperado com qualquer tipo de dados, exceto com matriz de matrizes,
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}"
o "efeito colateral" é explodir todas as matrizes em um conjunto de elementos.
PS: com arrays JSONB funciona bem,
SELECT array_distinct( array['[3,3]'::JSONB, '[3,3]'::JSONB, '[5,6]'::JSONB] ); -- "{"[3, 3]","[5, 6]"}"
Editar: mais complexo, mas útil, um parâmetro "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;
fonte
Eu montei um conjunto de stored procedures (funções) para combater a falta de manipulação de array do PostgreSQL
anyarray
. Essas funções são projetadas para funcionar em qualquer tipo de dados de array, não apenas inteiros como o intarray faz: https://www.github.com/JDBurnZ/anyarrayNo seu caso, tudo o que você realmente precisa é
anyarray_uniq.sql
. Copie e cole o conteúdo desse arquivo em uma consulta PostgreSQL e execute-o para adicionar a função. Se você também precisar de classificação de array, adicione tambémanyarray_sort.sql
.A partir daí, você pode realizar uma consulta simples da seguinte maneira:
SELECT ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234])
Retorna algo semelhante a:
ARRAY[1234, 6353, 5343]
Ou se você precisar de classificação:
SELECT ANYARRAY_SORT(ANYARRAY_UNIQ(ARRAY[1234,5343,6353,1234,1234]))
Retorne exatamente:
ARRAY[1234, 5343, 6353]
fonte
Usando
DISTINCT
implicitamente classifica a matriz. Se a ordem relativa dos elementos da matriz precisa ser preservada ao remover duplicatas, a função pode ser projetada da seguinte forma: (deve funcionar a partir de 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;
fonte
Esta é a maneira "embutida":
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;
Primeiro criamos um conjunto de array, depois selecionamos apenas entradas distintas e, em seguida, agregamos de volta ao array.
fonte
SELECT array_agg(DISTINCT c1) FROM unnest(ARRAY[1234,5343,6353,1234,1234]) t(c1)
Em uma única consulta, fiz o seguinte:
SELECT (select array_agg(distinct val) from ( select unnest(:array_column) as val ) as u ) FROM :your_table;
fonte
Para pessoas como eu, que ainda precisam lidar com o postgres 8.2, esta função recursiva pode eliminar duplicatas sem alterar a classificação do array
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;
por exemplo :
select my_array_uniq(array[3,3,8,2,6,6,2,3,4,1,1,6,2,2,3,99]);
darei
fonte