MySQL与多对多关系的限制

时间:2020-03-06 15:04:37  来源:igfitidea点击:

给出了用于实施标签的SCHEMA

物品
ItemId,ItemContent

标签
TagId,TagName

ITEM_TAG
ItemId,TagId

用标签选择时,限制返回的ITEMS数量的最佳方法是什么?

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中的行数。

解决方案

也许像

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

我的第一个建议是使用子查询来生成商品ID的列表,并返回与那些商品ID匹配的商品。但这不包括结果集中的TagName。我将使用另一种解决方案提交单独的答案。

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引擎应将其分解出来并仅运行一次。

我的第二个解决方案使用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 DISTINCT TagID,TagName FROM((TAG T
INNER JOIN ITEM_TAG I_T ON T.TagID = I_T.TagID)
内联项目I ON I_T.ItemID = I.ItemID)
TagID,TagName的分组