PostgreSQL DBにrestaurant
テーブルを含むかなり標準的なレストランモデルがあります。すべてのレストランには評価があります(これはaverage
、vote_count
、vote_sum
で構成されています)。たとえば、pictures
に対してこの評価スキーマを繰り返さないようにするために、rating
テーブルを個別に移動し、rating_id
のみを保存しましたrestaurant
内。
データベース全体で1つの評価が他の1つの行でのみ使用されることを知っています。 rating
またはrestaurant
の行を削除するときに、picture
に削除をカスケードする方法を教えてください。
私は周りを見回していますが、見つけることができるのはREFERENCES
を設定することだけですが、そのためにはどのテーブルデータが削除されるかを知る必要があります。
私はtriggersが仕事をすることを知っています、私は単にもっとエレガントなものを望んでいました。
いくつかの明確化:
REFERENCES
は、 FOREIGN KEY
constraint に使用されるキーワードWordです( カスケードDELETE
またはUPDATE
)。
データベースの設計に論理的な欠陥があるようです。 rating
は、メインテーブルrestaurant
の詳細のようです。 1対1の関係があるので、メインテーブルに「評価」列を含めるだけで済みます。別のテーブルが必要な場合は、逆の方法ではなくrating
テーブルにrestaurant_id
を含めます。
「評価」列average, vote_count and vote_sum
は別のテーブルvote
を示し、これらの値は派生集計です。 MATERIALIZED VIEW
がその典型的な解決策です。個別のrating
テーブルとして、または各メインテーブルの列と組み合わせて...
クリーンな方法は、メインテーブルごとに個別のrating
テーブルを用意することです。次に、ON DELETE CASCADE
を使用して、それぞれにFK制約を設定できます。
Ifまだ現在のデザインが必要な場合、2つのアイデアがあります。
rating
テーブル内の複数のFK列FK制約が正しい方向を指すように反転すると、テーブルは次のようになります。
CREATE TABLE rating (
rating_id serial PRIMARY KEY
, vote_count int
, vote_sum int
, average float8
, restaurant_id int UNIQUE REFERENCES restaurant(restaurant_id)
ON UPDATE CASCADE ON DELETE CASCADE
, picture_id int UNIQUE REFERENCES picture(picture_id)
ON UPDATE CASCADE ON DELETE CASCADE
-- more references to other tables
);
UNIQUE
制約は、1:1の要件を適用します。各マスターテーブルの各行は、rating
に最大でone行を持つことができます。また、非常に便利なインデックスを自動的に作成します。
あるいは、いくつかのメインテーブルがある場合は、各インデックスから無関係な行を除外するのではなく、部分的に一意のインデックスを作成することをお勧めします。
CREATE UNIQUE INDEX rating_restaurant_id ON rating (restaurant_id)
WHERE restaurant_id IS NOT NULL;
-- etc.
行ごとに1つのFK列のみを強制するには、NOT NULL
を使用します。
ALTER TABLE rating ADD CONSTRAINT exactly_one_fk CHECK (
(restaurant_id IS NOT NULL)::int
+ (picture_id IS NOT NULL)::int = 1); -- add more ...
いくつかのマスターテーブルがあると、大量の無駄なストレージのように見えるかもしれませんが、実際にはnotです。一連のNULL列はほとんどコストがかかりません。 NULLストレージは非常に安価です。
あなたの動機はto avoid repeating this rating schema
なので、 inheritance はあなたにとって良い解決策になるでしょう。 テーブル継承の制限 は、親テーブルの外部キーが継承されないことです-これはあなたの場合に有利になります:
CREATE TABLE rating (
rating_id serial PRIMARY KEY
, vote_count int
, vote_sum int
, average float8
);
CREATE TABLE restaurant_rating (
restaurant_id int PRIMARY KEY REFERENCES restaurant(restaurant_id)
ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (rating);
CREATE TABLE picture_rating (
picture_id int PRIMARY KEY REFERENCES picture (picture_id)
ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (rating);
-- more?
基本スキーマを一度だけ定義し、それから継承する必要があります。
単一のシーケンスが添付されたすべての評価に共通のPK列があります。
各子テーブルは、マスターテーブルのIDをPKおよびFKとして追加するため、1対1の関係が適用され、列に重要なインデックスが自動的に提供されます。
マスターテーブルにクエリを実行して、すべての評価を一度に取得できます。各行がどの子テーブルから発生したかを知る必要がある場合:
SELECT tableoid::regclass::text AS Origin, *
FROM rating;
マスターテーブルrating
への直接の挿入を禁止するルールまたはトリガーを追加することができます。
関連: