数据:
id data
1 1
1 4
2 2
2 1
3 3
3 2
4 4
4 1
5 5
5 2
我需要转动上述数据,以便得到以下结果:
id Col1 Col2
1 1 4
2 2 1
3 3 2
4 4 1
5 5 2
我正在尝试以下查询,但列始终为空:
DECLARE @TEMP TABLE (id int,data varchar(200))
INSERT INTO @TEMP VALUES (1,'1')
INSERT INTO @TEMP VALUES (1,'4')
INSERT INTO @TEMP VALUES (2,'2')
INSERT INTO @TEMP VALUES (2,'1')
INSERT INTO @TEMP VALUES (3,'3')
INSERT INTO @TEMP VALUES (4,'2')
INSERT INTO @TEMP VALUES (4,'4')
INSERT INTO @TEMP VALUES (4,'1')
INSERT INTO @TEMP VALUES (5,'5')
INSERT INTO @TEMP VALUES (5,'2')
SELECT * FROM @TEMP
PIVOT
(
MAX(Data)
FOR Data IN ([Col1],[Col2])
)
AS p
结果:
id Col1 Col2
1 NULL NULL
2 NULL NULL
3 NULL NULL
4 NULL NULL
5 NULL NULL
答案 0 :(得分:9)
您的查询存在的问题是,您的Data
列中没有任何名为Col1
或Col2
的值。
当您编写PIVOT查询时,查询的关键部分是:
pivot
(
max(data) -- < these are the values that you need displayed in the new columns
for col in (Col1, Col2) -- < this is the new column names from existing values
) p
您的查询正在使用Col1
,Col2
,但这些内容未在任何地方定义,因此您将返回null
。
您目前没有任何可用作新列名称的内容。为了获得结果,您需要使用类似于row_number
的窗口函数来为每个id
生成唯一序列。基本语法为:
select id, Col1, Col2
from
(
select id, data,
col =
'Col'+
cast(row_number() over(partition by id
order by data) as varchar(2))
from yourtable
) d
pivot
(
max(data)
for col in (Col1, Col2)
) p;
见SQL Fiddle with Demo。您会注意到,在子查询中,我使用窗口函数来创建新列名Col1
,Col2
等。然后在轴中使用它。
现在针对您的情况,如果您将拥有未知数量的可能列,那么您将需要使用动态SQL。这将创建一个随后将执行的SQL字符串:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col)
from
(
select col =
'Col'+
cast(row_number() over(partition by id
order by data) as varchar(2))
from yourtable
) d
group by Col
order by col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT id, ' + @cols + '
from
(
select id, data,
col =
''Col''+
cast(row_number() over(partition by id
order by data) as varchar(2))
from yourtable
) x
pivot
(
max(Data)
for col in (' + @cols + ')
) p '
exec sp_executesql @query;
最后,通过使用带有CASE表达式的聚合函数,也可以在不使用PIVOT的情况下完成此操作:
select id,
Col1 = max(case when seq = 1 then data end),
Col2 = max(case when seq = 2 then data end)
from
(
select id, data,
seq = row_number() over(partition by id
order by data)
from yourtable
) d
group by id;
见SQL Fiddle with Demo。所有版本都给出相同的结果:
| ID | COL1 | COL2 |
|----|------|------|
| 1 | 1 | 4 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| 4 | 1 | 4 |
| 5 | 2 | 5 |
答案 1 :(得分:3)
您可以在没有PIVOT
的情况下执行此操作:
;WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) RN
FROM @TEMP)
SELECT DISTINCT t.id, c1.data, c2.data
FROM @temp t
INNER JOIN CTE c1 ON c1.id = t.id AND c1.rn = 1
INNER JOIN CTE c2 ON c2.id = t.id AND c2.rn = 2
请注意,这将适用于此特定情况。但是,您应该尝试理解@ bluefeet的答案,以便彻底了解PIVOT
如何工作以及如果您在另一个场景中有多个列,您将如何使用它。