我有三个简单的表格:
产品
ItemID (int, PK)
ItemName (nvarchar50)
ItemCost (int)
标签
TagID (int, PK)
TagName (nvarchar50)
ItemTags
ItemID (int, FK->Items)
TagID (int, FK->Tags)
如何编写查询以查找标记为tag1和tag2的所有项目,而不是tag3'?
我是否需要使用完全不同的架构?
答案 0 :(得分:5)
我喜欢使用GROUP BY
和HAVING
:
SELECT it.ItemId
FROM ItemTags it JOIN
Tags t
ON t.TagId = it.TagId
GROUP BY it.ItemId
HAVING SUM(CASE WHEN t.TagName = 'Tag1' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN t.TagName = 'Tag2' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN t.TagName = 'Tag3' THEN 1 ELSE 0 END) = 0;
HAVING
子句中的每个条件都会检查一个标记。前两个使用> 0
来表示该项必须存在标记。第三个使用= 0
来表示该项目的标签不得存在。
答案 1 :(得分:1)
您可以使用OUTER APPLY:
SELECT i.*
FROM Items i
OUTER APPLY (
SELECT COUNT(*) as TagsCount
FROM ItemTags it
INNER JOIN Tags t
ON t.TagID = it.TagID
WHERE i.ItemID = it.ItemID
AND t.TagName IN ('tag1','tag2')
) as tt
WHERE TagsCount = 2
首先,我们得到所有ItemID
的{{1}}个。{然后加入TagsID
表,只过滤那些Items
修改#1 强>
添加样本:
TagsCount = 2
输出:
;WITH Items AS (
SELECT *
FROM (VALUES
(1,'Item1',100),(2,'Item2',50),(3,'Item3',90),(4,'Item4',63),(5,'Item5',75)
)as t(ItemID,ItemName,ItemCost)
)
, Tags AS (
SELECT *
FROM (VALUES
(1,'tag1'),(2,'tag2'),(3,'tag3'),(4,'tag4'),(5,'tag5')
) as t(TagID, TagName)
)
, ItemTags AS (
SELECT *
FROM (VALUES
(1,1),(1,2), --This
(2,1),(2,2),(2,3), --and that records we need to get
(3,1), (3,3),(3,4),
(4,2), (4,5),
(5,1)
) as t(ItemID, TagID)
)
SELECT i.*
FROM Items i
CROSS APPLY (
SELECT COUNT(*) as TagsCount
FROM ItemTags it
INNER JOIN Tags t
ON t.TagID = it.TagID
WHERE i.ItemID = it.ItemID
AND t.TagName IN ('tag1','tag2')
HAVING COUNT(*) = 2
) as tt
修改#2 强>
如果您要过滤没有ItemID ItemName ItemCost
1 Item1 100
2 Item2 50
标记的项目,可以添加左连接。
tag3
如果你想过滤某些标签你可以使用临时表和包含一个标签的项目,并且有你不需要的标签然后加入它们。动态SQL也可以是一种选择。
答案 2 :(得分:0)
这里有一个更简单的解决方案
let filteredTags = Set<Tag.ID>()
CREATE TABLE sketch (
id int
)
CREATE TABLE tag (
id int
)
CREATE TABLE sketchTag (
sketchId int,
tagId int
)
SELECT *
FROM sketch
INNER JOIN (
SELECT sketchId
FROM sketchTag
WHERE tagId IN \(filteredTags)
GROUP BY sketchId
HAVING COUNT(tagId) = \(filteredTags.count)
) AS sketchTag
ON sketch.id = sketchTag.sketchId