6

次のようなSQLテーブルがあります。

更新: 元のデータ (州、都市、学校) の既存の階層的な性質が、項目間に単純な関係が必要であるという事実を覆い隠しているため、サンプル テーブルを変更しています。

entities
id      name               
1       Apple     
2       Orange            
3       Banana             
4       Carrot                
5       Mushroom        

これらのエンティティ間の双方向の関係を定義して、1 つのエンティティを表示しているユーザーが関連するすべてのエンティティのリストを表示できるようにしたいと考えています。

関係は、エンド ユーザーによって定義されます。

これらの関係をデータベースで表現し、その後クエリを実行して更新する最良の方法は何ですか?

見たところ一通り…

私の直感では、リレーションシップ テーブルは次のようになります。

entity_entity
entity_id_a       entity_id_b
1                 2
5                 1
4                 1
5                 4
1                 3

その場合、指定された entity_id が 4 の場合、関連するすべてのレコード (1 と 5) を取得するにはどうすればよいでしょうか?

同様に、entity_id = 1 のクエリは、2、3、4、および 5 を返す必要があります。

お時間をいただきありがとうございます。質問を明確にすることができるかどうかお知らせください。

4

8 に答える 8

11

制約を定義します: 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すべてを選択するためだけに使用するためです。onはonよりも高速になります。abRANGE SCANix_bSKIP SCANix_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とは決して関係がない

于 2009-01-23T19:30:42.420 に答える
1

ご指摘の構造でいいと思います。

関連するレコードを取得するには、次のようにします

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'

それが役立つことを願っています。

于 2009-01-23T19:25:40.340 に答える
1

リンクテーブルのアプローチは問題ないように思えますが、「関係タイプ」が必要な場合があり、それらが関連している理由を知ることができます。

たとえば、ローリーとノースカロライナの関係は、ローリーとダーラムの関係と同じではありません。さらに、条件付きドロップダウンを実行している場合は、関係の「親」が誰であるかを知りたい場合があります。(つまり、州を選択すると、その州にある都市が表示されます)。

要件の複雑さによっては、現在の単純な設定では不十分な場合があります。2 つのレコードが何らかの方法で関連付けられていることを単に示す必要がある場合は、リンク テーブルで十分です。

于 2009-01-23T19:35:12.833 に答える
1

私はすでにあなたのデザインでそれを行う方法を投稿しましたが、あなたのデザインにある程度の柔軟性があり、これがあなたのニーズによりぴったり合っている場合は、この別のデザインの洞察を提供したいと思いました.

項目が (重複しない) 同等クラスにある場合、クラス内のすべてが同等と見なされるように、同等クラスをテーブル設計の基礎にすることができます。クラス自体は匿名にすることができます。

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
于 2009-01-23T19:40:21.153 に答える
0

更新されたスキーマに基づいて、このクエリは機能するはずです。

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)

ここで、:entity_idは、クエリしているエンティティにバインドされています

于 2009-01-23T21:08:52.147 に答える
0
select * from entities
where entity_id in 
(
    select entity_id_b 
    from entity_entity 
    where entity_id_a = @lookup_value
)
于 2009-01-23T19:26:16.220 に答える
0

いくつかの方法が考えられます。

CASE を使用した 1 つのパス:

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

または、次のように UNIONed された 2 つのフィルター処理されたクエリ:

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
于 2009-01-23T19:31:43.090 に答える