I have tried looking for a solution to my problem using things such as Pivot, but they do not seem to give the output for which I am looking as they appear to map specific values in a row to a column.
I have two columns, the first which contains a "key" field and the second which is changing data. e.g.
╔══════════╦══════════════════╗
║ Project ║ Location ║
╠══════════╬══════════════════╣
║ ProjectA ║ \\Server1\Share1 ║
║ ProjectA ║ \\Server2\Share1 ║
║ ProjectB ║ \\Server6\Share2 ║
║ ProjectB ║ \\Server1\Share2 ║
║ ProjectB ║ \\Server2\Share3 ║
║ ProjectC ║ \\Server8\Share2 ║
║ ProjectD ║ \\Server5\Share9 ║
║ ProjectD ║ \\ServerX\ShareY ║
╚══════════╩══════════════════╝
The output that I am trying to achieve is as follows:
╔══════════╦══════════════════╦══════════════════╦══════════════════╦═════════╦══════════╦═════════╗
║ Project ║ Column1 ║ Column2 ║ Column3 ║ Column4 ║ Column5 ║ ColumnX ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬═════════╬══════════╬═════════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩═════════╩══════════╩═════════╝
If there is no data for the column then it will be NULL.
The number of distinct values in the location column is dynamic and the desired output is a generic column name, with the distinct location value beside the corresponding Project value.
Hopefully someone can help me with this problem as it is driving me mad!
Thanks in advance.
Ninja
Warning:
This solution assume that it will be max 6 column, you can add more for example up to 20.
LiveDemo
Data:
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
Query:
WITH cte AS
(
SELECT Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
FROM #mytable
)
SELECT
Project
,Column1 = MAX(CASE WHEN rn = 1 THEN Location ELSE NULL END)
,Column2 = MAX(CASE WHEN rn = 2 THEN Location ELSE NULL END)
,Column3 = MAX(CASE WHEN rn = 3 THEN Location ELSE NULL END)
,Column4 = MAX(CASE WHEN rn = 4 THEN Location ELSE NULL END)
,Column5 = MAX(CASE WHEN rn = 5 THEN Location ELSE NULL END)
,Column6 = MAX(CASE WHEN rn = 6 THEN Location ELSE NULL END)
-- ....
-- ,ColumnX = MAX(CASE WHEN rn = X THEN Location ELSE NULL END)
FROM cte
GROUP BY Project;
Truly generic solution that uses Dynamic-SQL and generates Pivoted column list:
LiveDemo2
DECLARE @cols NVARCHAR(MAX),
@cols_piv NVARCHAR(MAX),
@query NVARCHAR(MAX)
,@max INT = 0;
SELECT @max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET @cols = STUFF(
(SELECT ',' + CONCAT('[',c.n, '] AS Column',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,'');
-- SELECT @cols;
set @query = N'SELECT Project, ' + @cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
) x
pivot
(
max(Location)
for rn in (' + @cols_piv + ')
) p ';
-- SELECT @query;
EXEC [dbo].[sp_executesql]
@query;
Credit goes to @lad2025.
I am using Server2005 so these are the modifications that I had to make to get this to work for me:
@max INT = 0;CONCAT function doesn't exist so replaced with + between the parameters. ', ' + '[' + convert(varchar, c.n) + '] AS Column' + c.nCONVERT it to VARCHAR - CONVERT(VARCHAR, c.n)GROUP BY needs to be provided otherwise the data appears in a strange column number.Without GROUP BY
Without the GROUP BY as more data is in the initial #mytable the results display in columns that are not sequential.
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════════════════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════════════════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ NULL ║ \\Server5\Share9 ║ NULL ║ NULL ║ \\ServerX\ShareY ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════════════════╩══════╝
With GROUP BY As it should be.
╔══════════╦══════════════════╦══════════════════╦══════════════════╦══════╦══════╦══════╗
║ Project ║ Col1 ║ Col2 ║ Col3 ║ Col4 ║ Col5 ║ Col6 ║
╠══════════╬══════════════════╬══════════════════╬══════════════════╬══════╬══════╬══════╣
║ ProjectA ║ \\Server1\Share1 ║ \\Server2\Share1 ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectB ║ \\Server1\Share2 ║ \\Server2\Share3 ║ \\Server6\Share2 ║ NULL ║ NULL ║ NULL ║
║ ProjectC ║ \\Server8\Share2 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ ProjectD ║ \\Server5\Share9 ║ \\ServerX\ShareY ║ NULL ║ NULL ║ NULL ║ NULL ║
╚══════════╩══════════════════╩══════════════════╩══════════════════╩══════╩══════╩══════╝
Data:
CREATE TABLE #mytable(
Project VARCHAR(80) NOT NULL
,Location VARCHAR(160) NOT NULL
);
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server1\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectA','\\Server2\Share1');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server6\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server1\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectB','\\Server2\Share3');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectC','\\Server8\Share2');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\Server5\Share9');
INSERT INTO #mytable(Project,Location) VALUES ('ProjectD','\\ServerX\ShareY');
Query:
DECLARE @cols NVARCHAR(MAX),
@cols_piv NVARCHAR(MAX),
@query NVARCHAR(MAX)
,@max INT;
SELECT @max = MAX(c)
FROM (
SELECT Project, COUNT(DISTINCT Location) AS c
FROM #mytable
GROUP BY Project) AS s;
SET @cols = STUFF(
(SELECT ', ' + '[' + convert(varchar, c.n) + '] AS Column' + convert(varchar, 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 ',' + '[' + convert(varchar, 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 Project, ' + @cols + ' from
(
select Project, Location,
[rn] = RANK() OVER (PARTITION BY Project ORDER BY Location)
from #mytable
GROUP BY Project, Location
) x
pivot
(
max(Location)
for rn in (' + @cols_piv + ')
) p ';
EXEC [dbo].[sp_executesql]
@query;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With