「2つのテーブルから離れた」制約の適用


10

SQLで電気回路図をモデリングするときに問題が発生しました。キャプチャしたい構造は

  part ←────────── pin
                   
part_inst ←───── pin_inst

ここで、「inst」は「instance」の略です。

例えば、私のように持っているかもしれないpartとのLM358オペアンプpinの1OUT、1IN-、1IN +、GND、2IN +、2IN-、2OUT、およびV CC。次に、このパーツを回路図に配置して、a part_instと8を 作成しpin_instます。

データフィールドを無視して、スキーマでの最初の試みは

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial primary key,
    part_id bigint not null references parts
);
create table part_insts (
    part_inst_id bigserial primary key,
    part_id bigint not null references parts
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null references part_insts,
    pin_id bigint not null references pins
);

このスキーマの主な問題は、ということであるpin_instに接続する可能性があるpart_instpart_id=1するが、そのがpin持っていますpart_id=2

アプリケーションレベルではなくデータベースレベルでこの問題を回避したいと思います。それで、私はそれを強制するために主キーを変更しました。変更した行にを付けました--

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial,                                          --
    part_id bigint not null references parts,
    primary key (pin_id, part_id)                              --
);
create table part_insts (
    part_inst_id bigserial,                                    --
    part_id bigint not null references parts,
    primary key (part_inst_id, part_id)                        --
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,                              --
    pin_id bigint not null,                                    --
    part_id bigint not null references parts,                  --
    foreign key (part_inst_id, part_id) references part_insts, --
    foreign key (pin_id, part_id) references pins              --
);

この方法の不満は、主キーを汚染することです。私がを参照するところはどこでもpart_instpart_inst_idとの両方を追跡する必要があり part_idます。pin_inst.part_inst.part_id = pin_inst.pin.part_id過度に冗長にせずに制約を強制する別の方法はあり ますか?


pin_inst_id冗長性のあるものも削除できます。(part_inst_id, part_id, pin_id)を主キーとして使用できます。
ypercubeᵀᴹ

(a)1OUT、1IN-、1IN +、GND、2IN +、2IN-、2OUT、およびVCCは11ピンのインスタンスを生成しないのですか?(b)最初のスキーマがわかりません。ピンは複数のパーツで使用できませんか?1-Nではなく、ピンとパーツのNN関係が必要です。
Marcus Junius Brutus 14

@ user34332:(a)番号は名前の一部です。たとえば、「2OUT」は単一のピンです。これは、私が問題で話しているチップの概略図です。(b)同意しない。確かに2つのパーツにはVCC(正の電源電圧、「電圧[共通]コレクター])ピンがあるかもしれませんが、それらは論理的に異なるピンです。たとえば、1つのVCCピンは通常500 µAを消費し、別の1つは250 µAを消費します。
スノーボール2014

@Snowball サンプルデータを含むSQL-Fiddleを追加すると、他のユーザーがスキーマを理解しやすくなります。
ypercubeᵀᴹ

回答:


13

最小限のソリューション

根本的な解決策の1つは、pin_inst完全に削除することです。

  part ←────────── pin
                   
part_inst ←───── pin_inst

あなたの質問には、実際に冗長なテーブルが必要であることを示唆するものは何もありません。以下のためpinに関連付けられているのpart_instでは、一見pin関連するの秒part

これにより、コードが次のように簡略化されます。

create table part (    -- using singular terms for table names
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part
);

しかし、あなたのコメントは私たちがそれを逃れることはないことを明らかにしました...

pin_inst必要な場合の代替

part_idあなたがしたように含めることは、外部キー制約を持つ最も簡単な解決策です。外部キー制約を使用して「2つのテーブル」離れたテーブルを参照することはできません。

しかし、少なくとも主キーを「汚染」することなくやり遂げることができます。UNIQUE制約を追加します

create table part (
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, pin_id)         -- note sequence of columns
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, part_inst_id)
);
create table pin_inst (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,
    pin_id bigint not null,
    part_id bigint not,
    foreign key (part_id, pin_id) references pin,
    foreign key (part_id, part_inst_id) references part_inst
);

part_idはユニークな制約を最初に置きます。これは参照整合性には関係ありませんが、パフォーマンスにとって重要です。主キーはすでにpk列のインデックスを実装しています。一意の制約を実装する複数列インデックスの最初に他の列を置くことをお勧めします。これらの関連質問の下の詳細:

SOに関する質問:

トリガー付きの代替

より柔軟なトリガー関数を使用することもできますが、少し複雑でエラーが発生しやすく、少し厳密ではありません。利点:あなたはなしpart_inst.part_idで行うことができますpin.part_id...


にはいくつかの追加の列がありますがpin_insts、読みやすくするために省略しました(「データフィールドを無視しています[...]」)。たとえば、a pin_instは入力または出力としてマークされます。
スノーボール2014

@スノーボール:本当であることが簡単になったでしょう。私はあなたの解決策を少し拡張しました。
Erwin Brandstetter 2014

2
2番目の提案は私の状況に適しています。私は外部キーが主キー以外のものを参照できることを知りませんでした。
スノーボール2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.