Não há nenhuma maneira interna neste momento.
Como matrizes
Se você normalizá-los consistentemente ao salvar, poderá tratar os arrays como conjuntos, armazenando-os sempre classificados e desduplicados. Seria ótimo se o PostgreSQL tivesse uma função C embutida para fazer isso, mas não tem. Eu dei uma olhada em escrever um, mas a API de matriz C é horrível , então mesmo que eu tenha escrito um monte de extensões, eu apenas me afastei cuidadosamente desta.
Se você não se importa com o desempenho moderadamente nocivo, pode fazê-lo no SQL:
CREATE OR REPLACE FUNCTION array_uniq_sort(anyarray) RETURNS anyarray AS $$
SELECT array_agg(DISTINCT f ORDER BY f) FROM unnest($1) f;
$$ LANGUAGE sql IMMUTABLE;
em seguida, envolva todos os salvamentos em chamadas para
array_uniq_sort
ou aplicá-lo com um gatilho. Você pode então apenas comparar seus arrays para igualdade. Você pode evitar o array_uniq_sort
solicita dados do aplicativo se, em vez disso, você apenas fez a classificação/exclusivo no lado do aplicativo. Se você fizer isso por favor armazene seus "conjuntos" como colunas de matriz, como
text[]
, não texto delimitado por vírgula ou espaço. Consulte esta pergunta
por alguns dos motivos. Você precisa tomar cuidado com algumas coisas, como o fato de que as conversões entre arrays são mais rígidas do que as conversões entre seus tipos base. Por exemplo.:
regress=> SELECT 'a' = 'a'::varchar, 'b' = 'b'::varchar;
?column? | ?column?
----------+----------
t | t
(1 row)
regress=> SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
ERROR: operator does not exist: text[] = character varying[]
LINE 1: SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
regress=> SELECT ARRAY['a','b']::varchar[] = ARRAY['a','b']::varchar[];
?column?
----------
t
(1 row)
Essas colunas são indexáveis por GiST para operações como array-contém ou array-overlaps; veja a documentação do PostgreSQL sobre indexação de array.
Como linhas normalizadas
A outra opção é apenas armazenar linhas normalizadas com uma chave adequada. Eu ainda usaria
array_agg
para classificá-los e compará-los, pois as operações de conjunto SQL podem ser desajeitadas de usar para isso (especialmente devido à falta de uma operação de diferença de conjunto XOR / dupla face). Isso é geralmente conhecido como EAV (entity-attribute-value). Eu mesmo não sou fã, mas ele tem seu lugar ocasionalmente. Exceto que você o usaria sem o
value
componente. Você cria uma tabela:
CREATE TABLE item_attributes (
item_id integer references items(id),
attribute_name text,
primary key(item_id, attribute_name)
);
e insira uma linha para cada entrada de conjunto para cada item, em vez de cada item ter uma coluna com valor de matriz. A restrição exclusiva imposta pela chave primária garante que nenhum item possa ter duplicatas de um determinado atributo. A ordenação dos atributos é irrelevante/indefinida.
As comparações podem ser feitas com operadores de conjunto SQL como
EXCEPT
, ou usando array_agg(attribute_name ORDER BY attribute_name)
para formar matrizes classificadas de forma consistente para comparação. A indexação limita-se a determinar se um determinado item possui ou não um determinado atributo.
Pessoalmente, eu usaria matrizes sobre essa abordagem.
hstore
Você também pode usar hstores com valores vazios para armazenar conjuntos, pois hstore desduplica chaves.
jsonb
da versão 9.4 também funcionará para isso. regress=# create extension hstore;
CREATE EXTENSION
regress=# SELECT hstore('a => 1, b => 1') = hstore('b => 1, a => 1, b => 1');
?column?
----------
t
(1 row)
Só é realmente útil para tipos de texto, no entanto. por exemplo.:
regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
?column?
----------
f
(1 row)
e acho feio. Então, novamente, eu prefiro matrizes.
Somente para matrizes inteiras
O
intarray
A extensão fornece funções úteis e rápidas para tratar arrays como conjuntos. Eles estão disponíveis apenas para arrays inteiros, mas são realmente úteis.