对于像这样的表:
COL1 COL2 COL3 COL4
item1 7/29/13 cat blue
item3 7/29/13 fish purple
item1 7/30/13 rat green
item2 7/30/13 bat grey
item3 7/30/13 bird orange
你如何通过COL2 PIVOT获取行,所有其他列以COL1值重复作为块?
COL2 COL1 COL3 COL4 COL1 COL3 COL4 COL1 COL3 COL4
7/29/13 item1 cat blue item2 NULL NULL item3 fish purple
7/30/13 item1 rat green item2 bat grey item3 bird orange
答案 0 :(得分:2)
为了得到这个结果,你需要做一些事情:
col1
和col2
col1
,col3
和col4
要获取日期和项目的明确列表(col1和col2)以及现有表格中的值,您需要使用类似于以下内容的内容:
select t.col1, t.col2,
t2.col3, t2.col4,
row_number() over(partition by t.col2
order by t.col1) seq
from
(
select distinct t.col1, c.col2
from yourtable t
cross join
(
select distinct col2
from yourtable
) c
) t
left join yourtable t2
on t.col1 = t2.col1
and t.col2 = t2.col2;
见SQL Fiddle with Demo。获得此列表后,您将需要取消数据。有几种方法可以使用UNPIVOT函数或使用CROSS APPLY:
select d.col2,
col = col+'_'+cast(seq as varchar(10)),
value
from
(
select t.col1, t.col2,
t2.col3, t2.col4,
row_number() over(partition by t.col2
order by t.col1) seq
from
(
select distinct t.col1, c.col2
from yourtable t
cross join
(
select distinct col2
from yourtable
) c
) t
left join yourtable t2
on t.col1 = t2.col1
and t.col2 = t2.col2
) d
cross apply
(
select 'col1', col1 union all
select 'col3', col3 union all
select 'col4', col4
) c (col, value);
见SQL Fiddle with Demo。这将为您提供如下数据:
| COL2 | COL | VALUE |
-------------------------------------------------
| July, 29 2013 00:00:00+0000 | col1_1 | item1 |
| July, 29 2013 00:00:00+0000 | col3_1 | cat |
| July, 29 2013 00:00:00+0000 | col4_1 | blue |
| July, 29 2013 00:00:00+0000 | col1_2 | item2 |
| July, 29 2013 00:00:00+0000 | col3_2 | (null) |
| July, 29 2013 00:00:00+0000 | col4_2 | (null) |
最后,您将PIVOT函数应用于col
列中的项目:
select col2,
col1_1, col3_1, col4_1,
col1_2, col3_2, col4_2,
col1_3, col3_3, col4_3
from
(
select d.col2,
col = col+'_'+cast(seq as varchar(10)),
value
from
(
select t.col1, t.col2,
t2.col3, t2.col4,
row_number() over(partition by t.col2
order by t.col1) seq
from
(
select distinct t.col1, c.col2
from yourtable t
cross join
(
select distinct col2
from yourtable
) c
) t
left join yourtable t2
on t.col1 = t2.col1
and t.col2 = t2.col2
) d
cross apply
(
select 'col1', col1 union all
select 'col3', col3 union all
select 'col4', col4
) c (col, value)
) src
pivot
(
max(value)
for col in (col1_1, col3_1, col4_1,
col1_2, col3_2, col4_2,
col1_3, col3_3, col4_3)
)piv;
见SQL Fiddle with Demo。如果您具有未知数量的值,则可以使用动态SQL来获取结果:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(seq as varchar(10)))
from
(
select row_number() over(partition by col2
order by col1) seq
from yourtable
) t
cross apply
(
select 'col1', 1 union all
select 'col3', 2 union all
select 'col4', 3
) c (col, so)
group by col, seq, so
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT col2, ' + @cols + '
from
(
select d.col2,
col = col+''_''+cast(seq as varchar(10)),
value
from
(
select t.col1, t.col2,
t2.col3, t2.col4,
row_number() over(partition by t.col2
order by t.col1) seq
from
(
select distinct t.col1, c.col2
from yourtable t
cross join
(
select distinct col2
from yourtable
) c
) t
left join yourtable t2
on t.col1 = t2.col1
and t.col2 = t2.col2
) d
cross apply
(
select ''col1'', col1 union all
select ''col3'', col3 union all
select ''col4'', col4
) c (col, value)
) x
pivot
(
max(value)
for col in (' + @cols + ')
) p '
execute sp_executesql @query;
见SQL Fiddle with Demo。所有版本都会给出结果:
| COL2 | COL1_1 | COL3_1 | COL4_1 | COL1_2 | COL3_2 | COL4_2 | COL1_3 | COL3_3 | COL4_3 |
----------------------------------------------------------------------------------------------------------------
| July, 29 2013 00:00:00+0000 | item1 | cat | blue | item2 | (null) | (null) | item3 | fish | purple |
| July, 30 2013 00:00:00+0000 | item1 | rat | green | item2 | bat | grey | item3 | bird | orange |
答案 1 :(得分:0)
动态UNPIVOT
+ PIVOT
方法总是很酷,当为一组已知且有限的值做这类事情后,JOIN
的工作也很好(懒惰) SELECT
列表):
WITH cte AS (SELECT *,ROW_NUMBER() OVER (PARTITION BY COL2 ORDER BY COL1)'RowRank'
FROM #Table1)
SELECT *
FROM cte a
LEFT JOIN cte b
ON a.COL2 = b.COL2
AND a.RowRank = b.RowRank - 1
LEFT JOIN cte c
ON b.COL2 = c.COL2
AND b.RowRank = c.RowRank - 1
WHERE a.RowRank = 1
或者如果要维护字段的顺序:
WITH cte AS (SELECT a.*,b.RowRank
FROM #Table1 a
JOIN (SELECT Col1,ROW_NUMBER() OVER (ORDER BY Col1)'RowRank'
FROM #Table1
GROUP BY COL1) b
ON a.Col1 = b.Col1)
SELECT *
FROM cte a
LEFT JOIN cte b
ON a.COL2 = b.COL2
AND a.RowRank = b.RowRank - 1
LEFT JOIN cte c
ON a.COL2 = c.COL2
AND a.RowRank = c.RowRank - 2
WHERE a.RowRank = 1
但是如果没有“锚”值,这就会崩溃,即如果某个日期没有记录item1
,那么它就不会被包含在内。