配列として保存(非正規化)
追加のモジュールuniq()
を提供します およびsort()
。典型的な最新のPostgresインストールでは、次のように簡単です。
CREATE EXTENSION intarray;
これらを使用して、簡単なCHECK
制約は昇順を強制できます 明確なの配列 要素。
CHECK (uniq(sort(cat_arr)) = cat_arr)
さらに (オプションで)配列値を正規化するトリガーがありますON INSERT OR UPDATE
自動的。次に、任意のを渡すだけです。 配列(おそらくソートされておらず、重複あり)とすべてが正常に機能します。いいね:
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();
追加のモジュールintarrayはオプションですが、他の方法があります。
ただし、intarray関数は優れたパフォーマンスを提供します。
次に UNIQUE
を作成するだけです 制約 配列列に配置して、配列全体の一意性を強制します。
UNIQUE (cat_arr)
ちょうど2日前に、この関連する回答で、(非常に厳密で信頼性の高い)制約と(信頼性は低いがより便利な)トリガーを組み合わせる利点について詳しく説明しました。
組み合わせごとに、カテゴリごとに保存する必要があるのがIDだけ(追加情報なし)の場合、これで十分です。
ただし 、参照整合性は、この方法では簡単に保証されません。配列要素には(まだ)外部キー制約はありません-リンクに記載されています
:カテゴリの1つが削除されたり、IDを変更したりすると、参照が壊れます...
正規化されたスキーマ
より多くを格納する必要がある場合、または参照整合性を適用するために正規化されたスキーマを使用する場合、または何らかの理由でそれを行うこともできます。トリガーを追加して、手作りのマテリアライズドビュー(冗長テーブル)にデータを入力します。同様の方法で一意性を適用します:
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)
);
トリガーを示す関連する回答(一意の組み合わせではなく、一意の要素):