Выберите в отношении многие ко многим в MySQL - PullRequest
5 голосов
/ 09 июня 2010

У меня есть две таблицы в базе данных MySQL, Locations и Tags, и третья таблица 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)

Таким образом, каждое местоположение может быть помечено несколькими тегами, а каждое слово может быть помечено в нескольких местах.

Что я хочу сделать, это выбрать только местоположения, которые помечены всеми именами тегов . Например:

Я хочу, чтобы все местоположения были помечены как "деревья" и "качели". Местоположение «Парк» следует выбирать, но местоположение «Лес» не следует.

Любое понимание будет оценено. Спасибо!

Ответы [ 2 ]

7 голосов
/ 09 июня 2010

Есть два способа сделать это. Я предпочитаю первый способ, который заключается в самостоятельном объединении для каждого тега:

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;
0 голосов
/ 09 июня 2010

Вам нужны места, где не существует заданный тег, который не отображается в таблице LocationsTagsAssoc с указанием местоположения.

Вы можете указать данные теги с помощью IN (), как показано ниже, или присоединиться к другой таблице, содержащей их.

* 1005 Т.е. *

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,...)
)
...