PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Armazenar e comparar combinações únicas

Armazenar como array (desnormalizado)


Eu consideraria o módulo adicional intarray que fornece as funções convenientes (e rápidas) uniq() e sort() . Em uma instalação moderna típica do Postgres, é tão fácil quanto:
CREATE EXTENSION intarray;

Usando estes, um simples CHECK restrição pode impor ascendente matrizes com distintas elementos.
CHECK (uniq(sort(cat_arr)) = cat_arr)

Você pode adicionalmente (opcionalmente) tem um gatilho que normaliza os valores do array ON INSERT OR UPDATE automaticamente. Então você pode simplesmente passar qualquer array (possivelmente não classificado e com dupes) e tudo funciona. Curti:
CREATE OR REPLACE FUNCTION trg_search_insup_bef()
  RETURNS trigger AS
$func$
BEGIN
   NEW.cat_arr := uniq(sort(NEW.cat_arr);
   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF cat_arr ON search
FOR EACH ROW
EXECUTE PROCEDURE trg_search_insup_bef();

O módulo adicional intarray é opcional, existem outras formas:

Mas as funções do intarray oferecem desempenho superior.

Então você pode simplesmente criar um UNIQUE restrição na coluna da matriz para impor a exclusividade de toda a matriz.
UNIQUE (cat_arr)

Escrevi mais sobre as vantagens de combinar restrições (muito estritas e confiáveis) com gatilhos (menos confiáveis, mas mais convenientes) nesta resposta relacionada apenas dois dias atrás:

Se, para cada combinação, tudo o que você precisa armazenar por categoria é o ID (e nenhuma informação adicional), isso deve ser suficiente.
No entanto , a integridade referencial não é facilmente garantida dessa maneira. Não há restrições de chave estrangeira para elementos de matriz (ainda) - como documentado em seu link :Se uma das categorias for excluída ou você alterar os IDs, as referências serão quebradas ...

Esquema normalizado


Se você precisa armazenar mais ou prefere usar um esquema normalizado para impor integridade referencial ou por algum motivo, também pode fazer isso e adicionar um gatilho para preencher uma visualização materializada feita à mão (uma tabela redundante) e impor a exclusividade de maneira semelhante:
CREATE TABLE search (
  search_id serial PRIMARY KEY
, ... more columns
);

CREATE TABLE cat (
  cat_id serial PRIMARY KEY
, cat text NOT NULL
);

CREATE TABLE search_cat (
  search_id int REFERENCES search ON DELETE CASCADE
, cat_id    int REFERENCES cat
, PRIMARY KEY (search_id, cat_id)
);

Resposta relacionada (não para combinações únicas, mas para elementos únicos) que demonstra o gatilho: