我有两个列视图
Product Id Tag
----------------------
1 Leather
1 Watch
2 Red
2 Necklace
2 Pearl
我正在尝试为产品获取所有可能的标签组合:
1 Leather
1 Leather,Watch
2 Pearl
2 Pearl,Necklace
2 Pearl Necklace,Red
2 Necklace
2 Necklace, Red
2 Red
我发现并窃取了一些SQL,它给了我所有但不是小版本的完整列表,下面是它。
任何想法,它开始让我的头受伤。一个虚拟品脱的最佳答案。
SELECT ProductId,
(SELECT CAST(Tag + ', ' AS VARCHAR(MAX))
FROM ProductByTagView
WHERE Product.ProductId = ProductByTagView.ProductId
order by tag
FOR XML PATH ('')) AS Tags
FROM Product
答案 0 :(得分:3)
这是一种方式。
理论上它可以处理每个产品最多20个标签(受到数字表大小的限制)但我并没有费心去尝试。在我的桌面上,大约需要30秒才能生成65,535个带有16个标签的产品的结果。希望每个产品的实际标签数量远远少于此!
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
返回
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
答案 1 :(得分:0)
这样的东西?:
select a.ProductID, a.tag+','+b.tag from aView a cross join aView b where a.tag != b.tag union select ProductID, tag from aView
答案 2 :(得分:0)
我的回答:
假设您有一个带整数的辅助Numbers表。
DECLARE @s VARCHAR(5);
SET @s = 'ABCDE';
WITH Subsets AS (
SELECT CAST(SUBSTRING(@s, Number, 1) AS VARCHAR(5)) AS Token,
CAST('.'+CAST(Number AS CHAR(1))+'.' AS VARCHAR(11)) AS Permutation,
CAST(1 AS INT) AS Iteration
FROM dbo.Numbers WHERE Number BETWEEN 1 AND 5
UNION ALL
SELECT CAST(Token+SUBSTRING(@s, Number, 1) AS VARCHAR(5)) AS Token,
CAST(Permutation+CAST(Number AS CHAR(1))+'.' AS VARCHAR(11)) AS
Permutation,
s.Iteration + 1 AS Iteration
FROM Subsets s JOIN dbo.Numbers n ON s.Permutation NOT LIKE
'%.'+CAST(Number AS CHAR(1))+'.%' AND s.Iteration < 5 AND Number
BETWEEN 1 AND 5
--AND s.Iteration = (SELECT MAX(Iteration) FROM Subsets)
)
SELECT * FROM Subsets
WHERE Iteration = 5
ORDER BY Permutation
Token Permutation Iteration
----- ----------- -----------
ABCDE .1.2.3.4.5. 5
ABCED .1.2.3.5.4. 5
ABDCE .1.2.4.3.5. 5
(snip)
EDBCA .5.4.2.3.1. 5
EDCAB .5.4.3.1.2. 5
EDCBA .5.4.3.2.1. 5
(120 row(s) affected)
答案 3 :(得分:0)
正如@Andomar所说,这是一个最好用客户端语言解决的问题,我尝试了各种解决方案(谢谢你们),虽然似乎有些东西,特别是在Martin的回答中,问题是时间到了运行查询。
再次感谢你们。
艾力