web-dev-qa-db-ja.com

同じ外部テーブルからの正確にn個の複数の外部キーを持つレコードを格納する代わりの方法で、関係を繰り返すことはできません

singularsというエンティティとrelationshipsというエンティティがあるとします。

singularsエンティティを構成するには、正確に2つのrelationshipsが必要です。

pairの単数形は、relationshipsの他の場所で、任意の順序で繰り返すことはできません。

これをモデル化する1つの方法は次のようになります。

+----------------+
|relationships   |         +----------+
+----------------+         |singulars |
|id              |         +----------+
|singular_id_1   <---------+id        |
|singular_id_2   <---+     |attribute1|
|pair_description|         |attribute2|
|pair_date       |         |          |
|                |         +----------+
+----------------+

このパターンでは、relationshipsのどちらの側にも存在する可能性があるかどうか、singularsの両方の外部キーフィールドを確認する必要があります。順序は関係ありませんが、スキーマで定義されています...したがって、クエリはAND/ORグループとケースの数で終わります。

そのアプローチを拡張すると、singular_id_[n]を両側で入れ替えて、すべてのペアのtwoレコードを保存できます。これにより、いくつかのクエリの複雑さが解決されますが、さらに複雑になり、実行不可能になります。

中間テーブルを使用することは、1つの解決策のように思われます。

+----------------+       +-----------------------+
|relationships   |       |singulars_relationships|        +----------+
+----------------+       +-----------------------+        |singulars |
|id              <-------+relationship_id        |        +----------+
|pair_description|       |singular_id            +-------->id        |
|pair_date       |       |                       |        |attribute1|
|                |       +-----------------------+        |attribute2|
+----------------+                                        |          |
                                                          +----------+

したがって、レコードは次のようになる可能性があります。

+----------------------------------+
|relationships                     |
+----------------------------------+
|id   pair_description   pair_date |
+----------------------------------+
|1    Fizz buzz blitz    2022-02-20|
|2    Blitz buzz fizz    2022-02-22|
+----------------------------------+

+----------------------------------+
|singulars_relationships           |
+----------------------------------+
|relationship_id   singular_id     |
+----------------------------------+
|1                 1               |
|1                 2               |
|2                 3               |
|2                 4               |
+----------------------------------+

+-----------------------------+
|singulars                    |
+-----------------------------+
|id   attribute1   attribute2 |
+-----------------------------+
|1    Fizz         Blitz      |
|2    Buzz         Foo        |
|3    Bar          World      |
|4    Blorg        Hello      |
+-----------------------------+

そこで、singulars_relationshipsはペアが定義される場所です。 singular_idがそこに存在する場合は、すでにペアになっています。このパターンで発生する可能性のある1つの問題は、3つ以上のsingular_idrelationship_idに関連付けられ、「正確にn」の制約が損なわれる可能性があることです。

このタイプのシナリオの公式用語はありますか?そして、他の理論と代替?

6
groovenectar

このタイプのシナリオの公式用語はありますか?

はい。これは 対称関係 です。また、ここでの「関係」は「リレーショナルデータベース」と同じ意味です。 RDBMSは、関係の格納を中心に設計されたデータベース管理システムです。ただし、RDBMSには対称関係を保存するためのネイティブの方法がありません。 (a、b)と(b、a)などの両方のタプルを別々の行として格納するか、または何らかの規則を使用して1つのタプルのみを格納する必要があります。一般的なアプローチは、FKにチェック制約を使用することです。

例えば

check (singular_id_1 < singular_id_2)

関係が 反反射 であると仮定します。

コメントを待ち望んでいるので、これを David's ソリューションの補足として追加します。質問は理論的な性質のものでしたが、それが実際の生活でどのように実装できるかを見るのは興味深いかもしれません。

いくつかの状況では、反射防止特性と対称特性が強すぎますが、それでも「一意性」特性を保持する必要があります。一般的なパターンの1つは、BEFORE TRIGGERSユーザーが対称プロパティを意識する必要なく、関係を対称にする:

CREATE TRIGGER trigger1
BEFORE INSERT ON t
REFERENCING NEW AS N
FOR EACH ROW
    SET (N.a, N.b) = (LEAST(N.a, N.b), GREATEST(N.a, N.b));

テーブルのプロパティ:

CHECK(a<=b);
UNIQUE(a,b);

このテーマのバリエーションは、生成された列を使用することです

CREATE TABLE t 
( a int not null
, b int not null
, least_a_b generated always as ( least(a,b) )
, greatest_a_b generated always as ( greatest(a,b))
, unique (least_a_b, greatest_a_b)
);

生成された列も非表示になる場合があります。

least_a_b generated always as ( least(a,b) ) IMPLICITLY HIDDEN

例はDb2からのものですが、他のベンダーにも同様の機能が存在するはずです。

7
Lennart