Pivoting Rows into Columns

Applicability:

SQL Server 2000: N/A

SQL Server 2005: Tested

SQL Server 2008: Tested

SQL Server 2008R2: Tested

SQL Server 2012: Tested

SQL Server 2014: Tested

SQL Server 2016: Tested

SQL Server 2017: Tested

Credits:

Author: ChillyDBA

Date: 10 Jun 2020

Description

This is not a script for direct use, but more of a template for use in other scripts.

This allows multiple rows from a single column to be pivoted with a delimiter into a single column on a single row. The resulting delimited string has no leading delimiter value.

The query can be a single table subquery, a correlated subquery, or a multi-join subquery of either type

The code here is wrapped in an example that will be easy to customize/test and which illustrates the output effectively.

Code

-- Conditionally drop the test table to make reruns easier.

IF OBJECT_ID('tempdb..#TestData','U') IS NOT NULL DROP TABLE #TestData;

CREATE TABLE #TestData (AccountNumber INT,

Value CHAR(3));


-- Build 1000 account numbers with random 3 character data.

;WITH

TENS (N) AS (SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL

SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL

SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0),

THOUSANDS (N) AS (SELECT 1 FROM TENS t1 CROSS JOIN TENS t2 CROSS JOIN TENS t3),

MILLIONS (N) AS (SELECT 1 FROM THOUSANDS t1 CROSS JOIN THOUSANDS t2),

TALLY (N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM MILLIONS)

INSERT INTO #TestData

SELECT TOP (100000)

AccountNumber = CASE WHEN (N%1000) = 0 THEN 1000 ELSE N%1000 END,

Value = CHAR(CONVERT(INT,RAND(CHECKSUM(NEWID()))*10)+64) +

CHAR(CONVERT(INT,RAND(CHECKSUM(NEWID()))*10)+64) +

CHAR(CONVERT(INT,RAND(CHECKSUM(NEWID()))*10)+64)

FROM TALLY;


-- Add a clustered index to the table

CREATE CLUSTERED INDEX IX_#TestData_Cover ON #TestData (AccountNumber, Value);



select * from #TestData




;WITH CTE AS

(

SELECT DISTINCT

AccountNumber

FROM #TestData

)

SELECT AccountNumber,

CommaList = STUFF((

SELECT ',' + Value

FROM #TestData

WHERE AccountNumber = CTE.AccountNumber

ORDER BY Value

FOR XML PATH(''),

TYPE).value('.','varchar(max)'),1,1,'')

FROM CTE

ORDER BY AccountNumber;

drop table #testdata