行を相互に関連付けることができるテーブルがあり、論理的には、2つの行の間の関係は双方向です(基本的に、方向がない)。 (そして、疑問に思っているのであれば、はい、これは実際には1つのテーブルである必要があります。これは、まったく同じ論理エンティティ/タイプの2つのものです。)これを表す方法はいくつか考えられます。
これらの方法の主な長所と短所は何ですか?もちろん、私が考えていない方法はありますか?
以下は、使用するSQLFiddleです: http://sqlfiddle.com/#!12/7ee1a/1/ 。 (私が使用しているため、PostgreSQLであるように思われますが、この質問はPostgreSQLに固有のものではないと思います。)現在、例として、関係とその逆の両方が格納されています。
あなたがデザインしたものは良いです。追加する必要があるのは、関係を無方向にするための制約です。したがって、(1,5)
行も追加しないと、(5,1)
行を作成できません。
これは達成することができます* ブリッジテーブルに自己参照制約があります。
*: sQL標準で記述されているように外部キー制約を実装しているPostgres、Oracle、DB2、およびすべてのDBMSで実行できます(遅延、たとえばトランザクションの最後にチェックされます。)SQL-Serverのように、遅延チェックは実際には必要ありません。ステートメントの最後にそれらをチェックし、この構造はまだ機能します。 MySQLではこれはできません "InnoDBは行ごとにUNIQUEおよびFOREIGN KEY制約をチェックします"。
したがって、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)に挿入
さらに、(y,y)
行を禁止する場合は、CHECK
制約を追加できます。
ALTER TABLE bridge_x
ADD CONSTRAINT x_x_self_referencing_items_not_allowed
CHECK (x_id1 <> x_id2) ;
x_id1
の低いIDとx_id2
列の高い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
);