SQLで電気回路図をモデリングする際に問題が発生しました。キャプチャしたい構造は
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
ここで、「inst」は「instance」の略です。
たとえば、part
としてpin
s 1OUT、1IN-、1IN +、GND、2IN +、2IN-、2OUT、およびVを備えたLM358オペアンプがあるとします。CC。次に、このパーツを回路図に配置して、part_inst
および8 pin_inst
sを作成します。
データフィールドを無視して、スキーマでの最初の試みは
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_inst
でpart_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_inst
を参照するすべての場所で、part_inst_id
とpart_id
の両方を追跡する必要があります。過度に冗長にせずにpin_inst.part_inst.part_id = pin_inst.pin.part_id
制約を適用する別の方法はありますか?
根本的な解決策の1つは、pin_inst
を完全に削除することです。
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
あなたの質問には、実際に冗長なテーブルが必要であることを示唆するものは何もありません。 part_inst
に関連付けられているpin
sについては、関連付けられているpin
のpart
sを確認してください。
これにより、コードが次のように簡略化されます。
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
constraint を追加します。
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列のインデックスを実装しています。一意の制約を実装する複数列インデックスの最初にother列を置くことをお勧めします。これらの関連質問の下の詳細:
SOに関する質問:
より柔軟なトリガー関数を使用することもできますが、少し複雑でエラーが発生しやすく、少し厳密ではありません。利点:part_inst.part_id
およびpin.part_id
なしで実行できる...