あなたがデザインしたものは良いです。追加する必要があるのは、関係を無方向にするための制約です。したがって、行を追加し(1,5)
ないと(5,1)
行を作成できません。
これを達成することができる*ブリッジテーブル上の自己参照制約を持ちます。
*:SQL標準で説明されているように外部キー制約を実装しているPostgres、Oracle、DB2、およびすべてのDBMSで実行できます(遅延、たとえばトランザクションの最後にチェックされます)。ステートメントの最後でそれらをチェックするサーバーであり、この構造は引き続き機能します。「InnoDBはUNIQUEおよびFOREIGN KEY制約を行ごとにチェックする」ため、これをMySQLで行うことはできません。
したがって、Postgresでは、以下が要件に一致します。
CREATE TABLE x
(
x_id SERIAL NOT NULL PRIMARY KEY,
data VARCHAR(10) NOT NULL
);
CREATE TABLE bridge_x
(
x_id1 INTEGER NOT NULL REFERENCES x (x_id),
x_id2 INTEGER NOT NULL REFERENCES x (x_id),
PRIMARY KEY(x_id1, x_id2),
CONSTRAINT x_x_directionless
FOREIGN KEY (x_id2, x_id1)
REFERENCES bridge_x (x_id1, x_id2)
);
テスト場所:SQL-Fiddle
行を追加しようとすると(1,5)
:
INSERT INTO bridge_x VALUES
(1,5) ;
それは失敗します:
エラー:テーブル "bridge_x"の挿入または更新が外部キー制約 "x_x_directionless"に違反しています
詳細:キー(x_id2、x_id1)=(5、1)がテーブル "bridge_x"に存在しません。:
INSERT INTO bridge_x VALUES(1,5)
さらに、行CHECK
を禁止する場合は、制約を追加でき(y,y)
ます。
ALTER TABLE bridge_x
ADD CONSTRAINT x_x_self_referencing_items_not_allowed
CHECK (x_id1 <> x_id2) ;
あなたが言及するようにこれを実装する他の方法があります。x_id1
たとえば、x_id2
列の低いID と高いIDを強制することによって、関係の1方向のみを(2行ではなく1行に)格納します。実装は簡単に見えますが、通常は後でより複雑なクエリにつながります。
CREATE TABLE bridge_x
(
x_id1 INTEGER NOT NULL REFERENCES x (x_id),
x_id2 INTEGER NOT NULL REFERENCES x (x_id),
PRIMARY KEY(x_id1, x_id2),
CONSTRAINT x_x_directionless
CHECK (x_id1 <= x_id2) -- or "<" to forbid `(y,y)` rows
);