我收到了以下格式的有序Microsoft Server表:
Name Product
------------------
1 | Mayer Product_1
2 | Mayer Product_1
3 | Mayer Product_2
我想获得以下结果:
Name Purchase_1 Purchase_2 Purchase_3
-----------------------------------------
1 | Mayer Product_1 Product_1 Product_2
代码必须适用于任意长度的购买和名称,这意味着我不能提前了解这些信息。
答案 0 :(得分:3)
动态PIVOT 是您的朋友:
CREATE TABLE #mytable(
Name VARCHAR(80) NOT NULL
,Product VARCHAR(160) NOT NULL
);
INSERT INTO #mytable VALUES ('Mayer','Product_1');
INSERT INTO #mytable VALUES ('Mayer','Product_1');
INSERT INTO #mytable VALUES ('Mayer','Product_2');
INSERT INTO #mytable VALUES ('Kowalsky','Product_1');
INSERT INTO #mytable VALUES ('Kowalsky','Product_2');
INSERT INTO #mytable VALUES ('Kowalsky','Product_3');
INSERT INTO #mytable VALUES ('Kowalsky','Product_4');
DECLARE @cols NVARCHAR(MAX),
@cols_piv NVARCHAR(MAX),
@query NVARCHAR(MAX)
,@max INT = 0;
SELECT @max = MAX(c)
FROM (
SELECT Name, COUNT(Product) AS c
FROM #mytable
GROUP BY Name) AS s;
SET @cols = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] AS Purchase_',c.n, ' ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @cols_piv = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] ')
FROM ( SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects ORDER BY n)AS c(n)
WHERE c.n <= @max
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @query = N'SELECT Name, ' + @cols + ' from
(
select Name, Product,
[rn] = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Product)
from #mytable
) x
pivot
(
max(Product)
for rn in (' + @cols_piv + ')
) p ';
-- SELECT @query;
EXEC [dbo].[sp_executesql]
@query;
起初可能很复杂,但这很简单。普通PIVOT
要求您事先知道列列表。这不是您的选择,因此您需要生成列并使用Dynamic-SQL。
工作原理:
@max
包含每行的最大列数@cols
包含带有别名的SELECT
列列表@cols_piv
包含数字列表[1], [2], ... @max
PIVOT
查询警告:强>
我使用sys.objects
作为我的号码生成器。您可以将其替换为您想要的(递归CTE /多步CTE /计数表...)。
如果您使用的是SQL Server 2008,则需要将CONCAT
替换为+
。