Ограничение MySQL с отношением "Многие ко многим"
Вопрос
Дана СХЕМА для реализации тегов
ПУНКТ Идентификатор элемента, содержимое элемента
ТЕГ Идентификатор тега, имя тега
ITEM_TAG Идентификатор элемента, TagID
Каков наилучший способ ограничить количество возвращаемых элементов при выборе с помощью тегов?
SELECT i.ItemContent, t.TagName FROM item i
INNER JOIN ItemTag it ON i.id = it.ItemId
INNER JOIN tag t ON t.id = it.TagId
это, конечно, самый простой способ вернуть их все обратно, но использование предложения limit приводит к сбоям, потому что вы получаете дубликат всех элементов для каждого тега, который засчитывается в количество строк в LIMIT.
Решение
Мое второе решение использует функцию MySQL GROUP_CONCAT() для объединения всех тегов, соответствующих элементу, в строку, разделенную запятыми, в результирующем наборе.
SELECT i.ItemContent, GROUP_CONCAT(t.TagName ORDER BY t.TagName) AS TagList
FROM item AS i
INNER JOIN ItemTag AS it ON i.id = it.ItemId
INNER JOIN tag AS t ON t.id = it.TagId
GROUP BY i.ItemId;
Функция GROUP_CONCAT() - это функция MySQL, она не является частью стандартного SQL.
Другие советы
Может быть, что-то вроде
select i.ItemContent, t.TagName from (SELECT ItemId, ItemContent FROM item limit 10) i
INNER JOIN ItemTag it ON i.ItemId = it.ItemId --You will miss tagless items here!
INNER JOIN tag t ON t.id = it.TagId
Мое первое предложение - использовать подзапрос для генерации списка идентификаторов элементов и возврата элементов, соответствующих этим идентификаторам элементов.Но это не включает имя тега в ваш результирующий набор.Я представлю отдельный ответ с другим решением.
SELECT i.ItemContent
FROM item AS i
WHERE i.id IN (
SELECT it.ItemId
FROM ItemTag AS it
INNER JOIN tag AS t ON (t.id = it.TagId)
WHERE t.TagName IN ('mysql', 'database', 'tags', 'tagging')
);
Это некоррелированный подзапрос, поэтому хороший движок SQL должен учитывать его и запускать только один раз.
Вы также могли бы использовать Distinct / Group By:
SELECT DISTINCT TagID, TagName FROM ((TAG T
INNER JOIN ITEM_TAG I_T ON T.TagID = I_T.TagID)
INNER JOIN ITEM I ON I_T.ItemID = I.ItemID)
GROUP BY TagID, TagName