Ecco un modo.
In teoria può gestire fino a 20 tag per prodotto (limitato dalle dimensioni della tabella dei numeri), tuttavia non mi sono preoccupato di provarlo. Sul mio desktop ci sono voluti circa 30 secondi per sfornare i 65.535 risultati per un singolo prodotto con 16 tag. Si spera che il numero effettivo di tag per prodotto sia molto inferiore a quello!
IF OBJECT_ID('tempdb..#Nums') IS NULL
BEGIN
CREATE TABLE #Nums
(
i int primary key
)
;WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B),
L5 AS (SELECT 1 AS c FROM L4 A CROSS JOIN L4 B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS i FROM L5)
INSERT INTO #Nums
SELECT TOP 1048576 i FROM Nums;
END
;with ProductTags As
(
SELECT 1 ProductId,'Leather' AS Tag UNION ALL
SELECT 1, 'Watch' UNION ALL
SELECT 2, 'Red' UNION ALL
SELECT 2, 'Necklace' UNION ALL
SELECT 2, 'Pearl'
), NumberedTags AS
(
SELECT
ProductId,Tag,
ROW_NUMBER() OVER (PARTITION BY ProductId ORDER BY Tag) rn,
COUNT(*) OVER (PARTITION BY ProductId) cn
FROM ProductTags
),
GroupedTags As
(
SELECT ProductId,Tag,i
FROM NumberedTags
JOIN #Nums on
#Nums.i < POWER ( 2 ,cn)
and #Nums.i & POWER ( 2 ,rn-1) > 0
)
SELECT ProductId,
STUFF((SELECT CAST(', ' + Tag AS VARCHAR(MAX))
FROM GroupedTags g2
WHERE g1.ProductId = g2.ProductId and g1.i = g2.i
ORDER BY Tag
FOR XML PATH ('')),1,1,'') AS Tags
FROM GroupedTags g1
GROUP BY ProductId, i
ORDER BY ProductId, i
Resi
ProductId Tags
----------- ------------------------------
1 Leather
1 Watch
1 Leather, Watch
2 Necklace
2 Pearl
2 Necklace, Pearl
2 Red
2 Necklace, Red
2 Pearl, Red
2 Necklace, Pearl, Red