PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Memorizzazione e confronto di combinazioni uniche

Memorizza come array (denormalizzato)

Prenderei in considerazione il modulo aggiuntivo intarray che fornisce le comode (e veloci) funzioni uniq() e sort() . In una tipica installazione moderna di Postgres è facile come:

CREATE EXTENSION intarray;

Usando questi, un semplice CHECK il vincolo può imporre il crescente array con distinti elementi.

CHECK (uniq(sort(cat_arr)) = cat_arr)

Puoi in aggiunta (facoltativamente) avere un trigger che normalizza i valori dell'array ON INSERT OR UPDATE automaticamente. Quindi puoi semplicemente passare qualsiasi array (possibilmente non ordinato e con duplicati) e tutto funziona. Come:

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();

Il modulo aggiuntivo intarray è opzionale, ci sono altri modi:

Ma le funzioni intraray offrono prestazioni superiori.

Allora puoi semplicemente creare un UNIQUE vincolo sulla colonna dell'array per imporre l'unicità dell'intero array.

UNIQUE (cat_arr)

Ho scritto di più sui vantaggi della combinazione di vincoli (molto severi e affidabili) con trigger (meno affidabili ma più convenienti) in questa risposta correlata solo due giorni fa:

Se, per ogni combinazione, tutto ciò che devi memorizzare per categoria è l'ID (e nessuna informazione aggiuntiva), questo dovrebbe essere abbastanza buono.
Tuttavia , l'integrità referenziale non è facilmente assicurata in questo modo. Non ci sono (ancora) vincoli di chiave esterna per gli elementi dell'array, come documentato nel tuo link :Se una delle categorie viene eliminata o si modificano gli ID, i riferimenti si interrompono...

Schema normalizzato

Se hai bisogno di archiviare di più o preferisci utilizzare uno schema normalizzato per imporre l'integrità referenziale o per qualche motivo, puoi farlo anche tu e aggiungere un trigger per popolare una vista materializzata fatta a mano (una tabella ridondante) e imporre l'unicità in modo simile:

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

Risposta correlata (non per combinazioni uniche, ma per elementi unici) che dimostra il trigger: