I got an ordered Microsoft Server table of the following form:
Name Product
------------------
1 | Mayer Product_1
2 | Mayer Product_1
3 | Mayer Product_2
And I would like to gain the following result:
Name Purchase_1 Purchase_2 Purchase_3
-----------------------------------------
1 | Mayer Product_1 Product_1 Product_2
The code has to work for an arbitrary length of purchases and names, meaning I don't know these information upfront.
Dynamic PIVOT is your friend :
LiveDEMO
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;
It may be complicated at first but this is really simple. Normal PIVOT
requires you to know column list in advance. This is not an option in your case so you need to generate column and use Dynamic-SQL.
How it works:
@max
contains max number of columns per row
@cols
contains SELECT
column list with aliases
@cols_piv
contains list of numbers [1], [2], ... @max
- Concatenate it with normal
PIVOT
query
- Execute it and enjoy your results.
Warning: