T-SQL-数据透视/交叉表-数量可变的值

时间:2018-07-23 14:39:18

标签: tsql

我有一个简单的数据集,如下所示:

Name    Code
A       A-One
A       A-Two
B       B-One
C       C-One
C       C-Two
C       C-Three 

我想输出它,就像这样:

Name    Code1    Code2    Code3    Code4    Code...n ...
A       A-One    A-Two
B       B-One
C       C-One    C-Two    C-Three

对于每个“名称”值,可以存在数量不确定的“代码”值。

我一直在研究Pivot SQL的各种示例(包括简单的Pivot sql和使用XML函数的sql吗?),但我一直无法弄清楚-甚至无法理解它是否可能。

我将不胜感激。

谢谢!

1 个答案:

答案 0 :(得分:1)

像这样尝试:

DECLARE @tbl TABLE([Name] VARCHAR(100),Code VARCHAR(100));
INSERT INTO @tbl VALUES
 ('A','A-One')
,('A','A-Two')
,('B','B-One')
,('C','C-One')
,('C','C-Two')
,('C','C-Three');

SELECT p.*
FROM 
(
    SELECT * 
          ,CONCAT('Code',ROW_NUMBER() OVER(PARTITION BY [Name] ORDER BY Code)) AS ColumnName
    FROM @tbl 
)t
PIVOT
(
    MAX(Code) FOR ColumnName IN (Code1,Code2,Code3,Code4,Code5 /*add as many as you need*/)
)p;

此行

,CONCAT('Code',ROW_NUMBER() OVER(PARTITION BY [Name] ORDER BY Code)) AS ColumnName

将使用分区的ROW_NUMBER,以便为每个代码创建编号为列名。其余的很简单PIVOT ...

更新:一种动态方法来反映每个组的最大代码量

CREATE TABLE TblTest([Name] VARCHAR(100),Code VARCHAR(100));
INSERT INTO TblTest VALUES
 ('A','A-One')
,('A','A-Two')
,('B','B-One')
,('C','C-One')
,('C','C-Two')
,('C','C-Three');

DECLARE @cols VARCHAR(MAX);
WITH GetMaxCount(mc) AS(SELECT TOP 1 COUNT([Code]) FROM TblTest GROUP BY [Name] ORDER BY COUNT([Code]) DESC)
SELECT @cols=STUFF(
(
    SELECT CONCAT(',Code',Nmbr)
    FROM
    (SELECT TOP((SELECT mc FROM GetMaxCount)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values) t(Nmbr)
    FOR XML PATH('')
),1,1,'');

DECLARE @sql VARCHAR(MAX)=
'SELECT p.*
FROM 
(
    SELECT * 
          ,CONCAT(''Code'',ROW_NUMBER() OVER(PARTITION BY [Name] ORDER BY Code)) AS ColumnName
    FROM TblTest 
)t
PIVOT
(
    MAX(Code) FOR ColumnName IN (' +  @cols + ')
)p;';

EXEC(@sql);
GO

DROP TABLE TblTest;

如您所见,为了反映实际的列数,唯一更改的部分是PIVOT的{​​{1}}子句中的列表。

您可以创建一个类似于IN()的字符串并动态生成该语句。可以通过Code1,Code2,Code3,...CodeN触发。

我更喜欢第一种方法。动态创建的SQL非常强大,但也可能会让人头痛...