MySQL Limit avec plusieurs relations
Question
Étant donné un SCHEMA pour l'implémentation des tags
ARTICLE ItemId, ItemContent
TAG TagId, TagName
ITEM_TAG ItemId, TagId
Quel est le meilleur moyen de limiter le nombre d’ÉLÉMENTS à renvoyer lors de la sélection avec des balises?
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
est bien sûr le moyen le plus simple de les récupérer tous les deux, mais l’utilisation d’une clause limit se décompose car vous obtenez une copie de tous les éléments de chaque balise, qui compte pour le nombre de lignes dans LIMIT.
La solution
Ma deuxième solution utilise une fonction MySQL GROUP_CONCAT () pour combiner toutes les balises correspondant à l'élément dans une chaîne séparée par des virgules dans le jeu de résultats.
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;
La fonction GROUP_CONCAT () est une fonctionnalité de MySQL, elle ne fait pas partie du SQL standard.
Autres conseils
Peut-être quelque chose comme
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
Ma première suggestion consiste à utiliser une sous-requête pour générer la liste des ID d'élément et renvoyer les éléments correspondant à ces ID. Mais cela n'inclut pas le TagName dans votre jeu de résultats. Je vais soumettre une réponse séparée avec une autre solution.
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')
);
Il s'agit d'une sous-requête non corrélée. Un bon moteur SQL doit donc en tenir compte et l'exécuter une seule fois.
Vous pouvez également utiliser 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