Reputation: 163
I have a table with 3 columns:
fileTagId: autoincrement, primary
fileId
tagId
multiple tags (tagId) can be associated with the same file (fileId), like so:
fileTagId | fileId | tagId
1 |1 | 4
2 |1 | 9
3 |1 | 12
4 |1 | 17
5 |2 | 4
6 |2 | 9
7 |2 | 19
8 |3 | 4
9 |3 | 7
10 |4 | 4
11 |5 | 32
12 |5 | 47
13 |5 | 49
14 |5 | 63
I wish to select all files (fileId) with a particular combination of tags (tagId) eg all files with tags 4 and 9 and it should return the following on the above table:
1
2
as only file number 1 and 2 have BOTH 4 AND 9 as tags
Upvotes: 0
Views: 36
Reputation: 2267
You can accomplish this by using STUFF or PIVOT like so :
SELECT DISTINCT FileId
FROM
(
SELECT FileId,
STUFF((SELECT ',' + CAST(TagId as varchar)
FROM #FileTag b
WHERE b.FileId = a.fileId
ORDER BY TagId
FOR XML PATH(''))
, 1, 1, '') AS NameList
FROM #fileTag a
) t
WHERE t.NameList like '%4,%9,%'
Or PIVOT
SELECT DISTINCT FileId
FROM
(
SELECT *
FROM
(
SELECT DISTINCT FileId, TagId
FROM #FileTag
) a
PIVOT (MAX(TagId) FOR TagId IN ([4], [9])) p
) t
where [4]+[9] IS NOT NULL
Upvotes: 1
Reputation: 1270573
I find that the most general way to approach these queries is using aggregating with a having
clause:
select fileid
from t
group by fileid
having sum(case when tagid = 4 then 1 else 0 end) > 0 and
sum(case when tagid = 9 then 1 else 0 end) > 0;
Each condition in the having
clause counts the number of rows that match one of the tags. You want at least one of each, hence the > 0
.
The reason I like this approach is because it is easy to add new conditions. Say you want 4 and 9 but not 6
having sum(case when tagid = 4 then 1 else 0 end) > 0 and
sum(case when tagid = 9 then 1 else 0 end) > 0 and
sum(case when tagid = 6 then 1 else 0 end) = 0;
Upvotes: 2