In other places where you can get examples of turning a CSV parameter into a table variable. Assuming you have completed this part, your query comes down to the following:
GetFacetedProducts: Find product records where all tags passed to are assigned to each product.
If you wrote this manually, you can end up with:
SELECT P.* FROM Product P INNER JOIN ProductTag PT1 ON PT1.ProductID = P.ID AND PT1.TagID = 1 INNER JOIN ProductTag PT2 ON PT1.ProductID = P.ID AND PT1.TagID = 3 INNER JOIN ProductTag PT3 ON PT1.ProductID = P.ID AND PT1.TagID = 5
While this selects only those products that have tags, it will not work with a dynamic list. In the past, some people created SQL and executed it dynamically, do not do this.
Instead, suppose that the same tag cannot be applied to the product twice, so we can change our question: Find products in which the number of tag matches (dynamic list) is equal to the number of tags in the dynamic list
DECLARE @selectedTags TABLE (ID int) DECLARE @tagCount int INSERT INTO @selectedTags VALUES (1) INSERT INTO @selectedTags VALUES (3) INSERT INTO @selectedTags VALUES (5) SELECT @tagCount = COUNT(*) FROM @selectedTags SELECT P.ID FROM Product P JOIN ProductTag PT ON PT.ProductID = P.ID JOIN @selectedTags T ON T.ID = PT.TagID GROUP BY P.ID, P.Name HAVING COUNT(PT.TagID) = @tagCount
This returns only the product identifier matching all your tags, after which you can join it back to the product table if you want more than just an identifier, otherwise you are done.
As in the second query, if you have product identifiers that match, you need a list of all tags for those product identifiers that are not listed on your list:
SELECT DISTINCT PT2.TagID FROM aProductTag PT2 WHERE PT2.ProductID IN ( SELECT P.ID FROM aProduct P JOIN aProductTag PT ON PT.ProductID = P.ID JOIN @selectedTags T ON T.ID = PT.TagID GROUP BY P.ID, P.Name HAVING COUNT(PT.TagID) = @tagCount ) AND PT2.TagID NOT IN (SELECT ID FROM @selectedTags)