5

MySQL データベースには Locations と Tags という 2 つのテーブルがあり、2 つのテーブルを関連付けて多対多の関係として扱う 3 つ目のテーブル LocationsTagsAssoc があります。

テーブル構造は次のとおりです。

Locations
---------
ID int (Primary Key)
Name varchar(128)

LocationsTagsAssoc
------------------
ID int (Primary Key)
LocationID int (Foreign Key)
TagID int (Foreign Key)

Tags
----
ID int (Primary Key)
Name varchar(128)

したがって、各場所は複数のタグワードでタグ付けでき、各タグワードは複数の場所にタグ付けできます。

私がやりたいことは、指定されたすべてのタグ名でタグ付けされた場所のみを選択することです。例えば:

「tree」と「swings」の両方でタグ付けされたすべての場所が必要です。場所「公園」を選択する必要がありますが、場所「森」は選択しないでください。

任意の洞察をいただければ幸いです。ありがとう!

4

2 に答える 2

9

これには 2 つの方法があります。私は、タグごとに自己結合する最初の方法を好みます。

SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a1 ON a1.LocationID = l.ID
JOIN Tags t1 ON a1.TagID = t1.ID AND t1.Name = ?
JOIN LocationsTagsAssoc a2 ON a2.LocationID = l.ID
JOIN Tags t2 ON a2.TagID = t2.ID AND t2.Name = ?
JOIN LocationsTagsAssoc a3 ON a3.LocationID = l.ID
JOIN Tags t3 ON a3.TagID = t3.ID AND t3.Name = ?;

他の方法も機能GROUP BYしますが、MySQL で使用すると一時テーブルが発生する傾向があり、パフォーマンスが低下します。

SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
WHERE t.Name IN (?, ?, ?)
GROUP BY l.ID
HAVING COUNT(*) = 3;

@Erikoenig からの再コメント:

余分なタグがないことを確認したい場合は、次の方法で行うことができます。

SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
GROUP BY l.ID
HAVING COUNT(*) = 3 AND SUM(t.Name IN (?, ?, ?)) = 3;

WHERE 句を削除すると、他のタグがあればそれをカウントできます。したがって、COUNT() は 3 より大きい場合があります。

または、カウントがちょうど 3 つのタグであるが、これらの 3 つのタグの一部が正しいタグではない場合、HAVING 句の SUM() 条件により、必要な 3 つのタグすべてがグループに存在することが確認されます。

于 2010-06-08T22:41:28.607 に答える
0

ロケーションの LocationsTagsAssoc テーブルに表示されない特定のタグが存在しないロケーションが必要です。

次のように IN () を使用して特定のタグを指定するか、それらを含む別のテーブルに結合することができます。

いえ

SELECT l.*
FROM Locations AS l
WHERE NOT EXISTS (
    SELECT NULL FROM Tags AS t
    WHERE NOT EXISTS (
        SELECT NULL FROM LocationsTagsAssoc AS lt
        WHERE lt.LocationId = l.ID
            AND lt.TagID = t.ID
    )
        AND t.ID IN (1, 2, 3,...)
)
于 2010-06-08T22:43:44.490 に答える