PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Speichern und Vergleichen einzigartiger Kombinationen

Als Array speichern (denormalisiert)

Ich würde das zusätzliche Modul intarray in Betracht ziehen die die bequemen (und schnellen) Funktionen uniq() bereitstellt und sort() . In einer typischen modernen Postgres-Installation ist es so einfach wie:

CREATE EXTENSION intarray;

Mit diesen ein einfacher CHECK Einschränkung kann aufsteigend erzwingen Arrays mit distinct Elemente.

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

Sie können zusätzlich (optional) einen Trigger haben, der Array-Werte normalisiert ON INSERT OR UPDATE automatisch. Dann kannst du einfach beliebig weitergeben Array (möglicherweise unsortiert und mit Dupes) und alles funktioniert einfach. Wie:

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

Das Zusatzmodul Intarray ist optional, es gibt andere Möglichkeiten:

Aber die Intarray-Funktionen liefern eine überlegene Leistung.

Dann Sie können einfach einen UNIQUE erstellen Einschränkung auf der Array-Spalte, um die Eindeutigkeit des gesamten Arrays zu erzwingen.

UNIQUE (cat_arr)

Ich habe erst vor zwei Tagen in dieser verwandten Antwort mehr über die Vorteile der Kombination von (sehr strengen und zuverlässigen) Einschränkungen mit (weniger zuverlässigen, aber bequemeren) Auslösern geschrieben:

Wenn Sie für jede Kombination nur die ID (und keine zusätzlichen Informationen) pro Kategorie speichern müssen, sollte dies ausreichen.
Allerdings , ist die referentielle Integrität auf diese Weise nicht einfach sicherzustellen. Es gibt (noch) keine Fremdschlüsselbeschränkungen für Array-Elemente - wie in Ihrem Link dokumentiert :Wenn eine der Kategorien gelöscht wird oder Sie IDs ändern, werden Referenzen unterbrochen ...

Normalisiertes Schema

Wenn Sie mehr speichern müssen oder lieber ein normalisiertes Schema verwenden möchten, um die referenzielle Integrität zu erzwingen, oder aus irgendeinem Grund, können Sie dies auch tun und einen Trigger hinzufügen, um eine handgefertigte materialisierte Ansicht (eine redundante Tabelle) zu füllen und Eindeutigkeit auf ähnliche Weise erzwingen:

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

Zugehörige Antwort (nicht für eindeutige Kombinationen, sondern für eindeutige Elemente), die den Auslöser demonstriert: