何が最良の方法は多対多の関係記録一SQLテーブルは?
-
19-08-2019 - |
質問
私は、SQLテーブルはこのように:
更新:私を変える例として、既存の階層の自然のオリジナルデータ(国家、都市、学校はovershadowing、この単純な関係が必要なのです。
entities
id name
1 Apple
2 Orange
3 Banana
4 Carrot
5 Mushroom
したい定義の双方向の関係をこれらの主体でユーザーの閲覧を一体でのリストをご参照くださいすべてのなんら関係がありません。
の関係によって定義される。
には、どうするのがベストな表現にこれらの関係データベースに、その後、クエリ、更新ですか。
片がって...
私の本能との関係をテーブルはこのように:
entity_entity
entity_id_a entity_id_b
1 2
5 1
4 1
5 4
1 3
このため、供給entity_id4、あなたは何点ぐらいになると思一の取得に関する記録は、1、5?
しも、予約も、支払も、全部エのentity_id=1を返します2,3,4,5.
お時間というべき道を明らかにすることができ、解決しなければならない問題です。
解決
制約を定義します:entity_id_a < entity_id_b
。
インデックスの作成:
CREATE UNIQUE INDEX ix_a_b ON entity_entity(entity_id_a, entity_id_b);
CREATE INDEX ix_b ON entity_entity(entity_id_b);
2番目のインデックスには、1つのentity_id_a
内のすべてのa
を選択するためにのみ使用するため、b
を含める必要はありません。 RANGE SCAN
のix_b
は、SKIP SCAN
のix_a_b
よりも高速です。
次のようにエンティティをテーブルに追加します。
INSERT
INTO entity_entity (entity_id_a, entity_id_b)
VALUES (LEAST(@id1, @id2), GREATEST(@id1, @id2))
次に選択:
SELECT entity_id_b
FROM entity_entity
WHERE entity_id_a = @id
UNION ALL
SELECT entity_id_a
FROM entity_entity
WHERE entity_id_b = @id
ここで UNION ALL
を使用すると、上記のインデックスを使用して、一意性のための余分なソートを回避できます。
上記のすべては、対称で反反射的な関係に有効です。つまり:
-
a が b に関連している場合、 b は a
に関連しています
-
a は a
とは関係ありません
他のヒント
あなたが提案した構造は素晴らしいと思います。
関連レコードを取得するには、次のようにします
SELECT related.* FROM entities AS search
LEFT JOIN entity_entity map ON map.entity_id_a = search.id
LEFT JOIN entities AS related ON map.entity_id_b = related.id
WHERE search.name = 'Search term'
役立つこと。
リンクテーブルのアプローチは問題ないように見えますが、「関係タイプ」が必要な場合があり、それらが関連している理由を知ることができます。
たとえば、ローリーとノースカロライナの関係は、ローリーとダーラムの関係とは異なります。さらに、条件付きドロップダウンを駆動している場合に備えて、関係の「親」が誰であるかを知りたい場合があります。 (つまり、州を選択すると、その州にある都市が表示されます)。
要件の複雑さによっては、現在の単純なセットアップでは不十分な場合があります。 2つのレコードが何らかの方法で関連していることを単に表示する必要がある場合は、リンクテーブルで十分です。
既にデザインでそれを行う方法を投稿しましたが、デザインにある程度の柔軟性があり、ニーズにより近い場合は、この個別のデザインの洞察を提供したかったです。
アイテムが(重複しない)等価クラスにある場合、等価クラスをテーブル設計の基礎にしたい場合があります。クラスのすべてが等価であると見なされます。クラス自体は匿名にすることができます:
CREATE TABLE equivalence_class (
class_id int -- surrogate, IDENTITY, autonumber, etc.
,entity_id int
)
entity_id
は、スペースの重複しないパーティションに対して一意である必要があります。
これにより、適切な左利きまたは右利きを確保する問題や、右上の関係マトリックスを強制する問題が回避されます。
クエリは少し異なります:
SELECT c2.entity_id
FROM equivalence_class c1
INNER JOIN equivalence_class c2
ON c1.entity_id = @entity_id
AND c1.class_id = c2.class_id
AND c2.entity_id <> @entity_id
または、同等:
SELECT c2.entity_id
FROM equivalence_class c1
INNER JOIN equivalence_class c2
ON c1.entity_id = @entity_id
AND c1.class_id = c2.class_id
AND c2.entity_id <> c1.entity_id
いくつかの方法が考えられます。
CASEのある単一パス:
SELECT DISTINCT
CASE
WHEN entity_id_a <> @entity_id THEN entity_id_a
WHEN entity_id_b <> @entity_id THEN entity_id_b
END AS equivalent_entity
FROM entity_entity
WHERE entity_id_a = @entity_id OR entity_id_b = @entity_id
または2つのフィルター処理されたクエリがUNIONされた場合:
SELECT entity_id_b AS equivalent_entity
FROM entity_entity
WHERE entity_id_a = @entity_id
UNION
SELECT entity_id_a AS equivalent_entity
FROM entity_entity
WHERE entity_id_b = @entity_id
select * from entities
where entity_id in
(
select entity_id_b
from entity_entity
where entity_id_a = @lookup_value
)
更新されたスキーマに基づいて、このクエリは機能するはずです:
select if(entity_id_a=:entity_id,entity_id_b,entity_id_a) as related_entity_id where :entity_id in (entity_id_a, entity_id_b)
where:entity_idは、クエリしているエンティティにバインドされています
私のアドバイスが初期テーブルのデザインは悪いものです。ない店舗の異なる種類のものと同じ。(最初のルールのデータベース設計には保管しないで複数の情報が同じである。これは、硬めのクエリが顕著なパフォーマンスの問題ました。スペシャル"ホットスポットが問題データの入力にrealtionshipテーブルからシステムについての主体が必要となる場合があるrealtedきました。になると思いますデザインを適切に関係す。企業のテーブルはほとんど常に悪い。思い当たらない理由ですべての例ではこのタイプの情報を一つの表に示す。率直に言って大学テーブルに関するアドレス。いやすいクエリを実行です。