sql >> Databasteknik >  >> RDS >> PostgreSQL

Lagra och jämföra unika kombinationer

Lagra som array (denormaliserad)

Jag skulle överväga tilläggsmodulen intarray som tillhandahåller de bekväma (och snabba) funktionerna uniq() och sort() . I en typisk modern Postgres-installation är det så enkelt som:

CREATE EXTENSION intarray;

Genom att använda dessa, en enkel CHECK begränsning kan tvinga fram stigande arrayer med distinkt element.

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

Du kan ytterligare (valfritt) ha en utlösare som normaliserar arrayvärden ON INSERT OR UPDATE automatiskt. Sedan kan du bara passera vilken som helst array (eventuellt osorterade och med duper) och allt bara fungerar. Gilla:

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

Den extra modulinsatsen är valfri, det finns andra sätt:

Men inmatrisfunktionerna ger överlägsen prestanda.

du kan bara skapa en UNIQUE begränsning på arraykolumnen för att framtvinga unikhet för hela arrayen.

UNIQUE (cat_arr)

Jag skrev mer om fördelarna med att kombinera (mycket strikta och pålitliga) begränsningar med (mindre tillförlitliga men bekvämare) utlösare i detta relaterade svar för bara två dagar sedan:

Om, för varje kombination, allt du behöver lagra per kategori är ID (och ingen ytterligare information), bör detta vara tillräckligt bra.
Men , är referensintegritet inte lätt att säkerställa på detta sätt. Det finns inga begränsningar för främmande nyckel för arrayelement (ännu) - som dokumenterade i din länk :Om en av kategorierna tas bort eller du ändrar ID:n bryter referenserna ...

Normaliserat schema

Om du behöver lagra mer eller om du hellre föredrar ett normaliserat schema för att upprätthålla referensintegritet eller av någon anledning kan du också göra det och lägga till en trigger för att fylla i en handgjord materialiserad vy (en redundant tabell) och framtvinga unikhet på liknande sätt:

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

Relaterat svar (inte för unika kombinationer, utan för unika element) som visar utlösaren:



  1. Skapa rollbaserad åtkomstkontroll i MongoDB

  2. JSON_REMOVE() – Ta bort data från ett JSON-dokument i MySQL

  3. Är det möjligt att anropa en posttyp inuti en markör?

  4. CakePHP rekursiv borttagning