这是一个与T-SQL相关的问题。我正在使用SQL Server 2012。
我有一张这样的表:
我希望输出如下:
说明:
对于每位员工,都会有一排。员工有一项或多项任务。 Batch Id指定了这一点。根据批次ID,列名称将更改(例如,国家1,国家2等)。
到目前为止的方法:
取消透视源表,如下所示:
select
EmpId, 'Country ' + cast(BatchId as varchar) as [ColumnName],
Country as [ColumnValue]
from
SourceTable
UNION
select
EmpId, 'Pass ' + cast(BatchId as varchar) as [ColumnName],
Pass as [ColumnValue]
from
SourceTable
将每列的值作为行。然后,可以旋转此结果以获得所需的输出。
问题:
答案 0 :(得分:2)
在SQL中执行它。
让SSRS通过 MATRIX 为您完成工作。它将为您提供PIVOT,而无需创建动态SQL来处理需要知道所有列的可怕限制。
对于您的数据,您可以将EMP ID作为ROW组,并将PASS作为列分组。
答案 1 :(得分:1)
有许多可能的解决方案可以实现您的目标(在多列上搜索 Dynamic Pivot )
<强> SqlFiddleDemo 强>
警告:我假设Country和Pass列不是NULL
CREATE TABLE SourceTable(EmpId INT, BatchId INT,
Country NVARCHAR(100) NOT NULL, Pass NVARCHAR(5) NOT NULL);
INSERT INTO SourceTable(EmpId, BatchId, Country, Pass)
VALUES
(100, 1, 'UK', 'M'), (200, 2, 'USA', 'U'),
(100, 2, 'Romania', 'M'), (100, 3, 'India', 'MA'),
(100, 4, 'Hongkong', 'MA'), (300, 1, 'Belgium', 'U'),
(300, 2, 'Poland', 'U'), (200, 1, 'Australia', 'M');
/* Get Number of Columns Groups Country1..Country<MaxCount> */
DECLARE @max_count INT
,@sql NVARCHAR(MAX) = ''
,@columns NVARCHAR(MAX) = ''
,@i INT = 0
,@i_s NVARCHAR(10);
WITH cte AS
(
SELECT EmpId
,[cnt] = COUNT(*)
FROM SourceTable
GROUP BY EmpId
)
SELECT @max_count = MAX(cnt)
FROM cte;
WHILE @i < @max_count
BEGIN
SET @i += 1;
SET @i_s = CAST(@i AS NVARCHAR(10));
SET @columns += N',MAX(CASE WHEN [row_no] = ' + @i_s + ' THEN Country END) AS Country' + @i_s +
',MAX(CASE WHEN [row_no] = ' + @i_s + ' THEN Pass END) AS Pass' + @i_s;
END
SELECT @sql =
N';WITH cte AS (
SELECT EmpId, Country, Pass, [row_no] = ROW_NUMBER() OVER (PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable)
SELECT EmpId ' + @columns + N'
FROM cte
GROUP BY EmpId';
/* Debug */
/* SELECT @sql */
EXEC(@sql);
或者:
<强> SQLFiddleDemo2 强>
DECLARE @cols NVARCHAR(MAX),
@sql NVARCHAR(MAX) = '';
;WITH cte(col_name, rn) AS(
SELECT DISTINCT col_name = col_name + CAST(BatchId AS VARCHAR(10)),
rn = ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable
CROSS APPLY (VALUES ('Country', Country), ('Pass', Pass)) AS c(col_name, val)
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(col_name)
FROM cte
ORDER BY rn /* If column order is important for you */
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SET @sql =
N';WITH cte AS
(
SELECT EmpId, col_name = col_name + CAST(BatchId AS VARCHAR(10)), val
FROM SourceTable
CROSS APPLY (VALUES (''Country'', Country), (''Pass'', Pass)) AS c(col_name, val)
)
SELECT *
FROM cte
PIVOT
(
MAX(val)
FOR col_name IN (' + @cols + ')
) piv';
EXEC(@sql);