SQL从单列到多列的多个日期

时间:2012-12-11 10:55:17

标签: sql sql-server sql-server-2008 tsql pivot

如何移动如下所示的日期列。

User              Date
====              ====
001               2012/12/01 09:00
001               2012/12/01 11:00
001               2012/12/01 12:00
001               2012/12/01 13:00
001..             ...        

并列出如下。

User  date         time1   time2   time3  time4    time5  
001   2012/12/01   09:00   11:00   12:00  13:00    14:00   

感谢Bluefeet的解决方案。我测试了脚本并得到了以下结果。

2   2012/11/04  09:00:00.000    NULL    NULL    NULL    NULL    NULL    NULL
2   2012/11/08  NULL    09:00:00.000    18:00:00.000    NULL    NULL    NULL    NULL
2   2012/11/09  NULL    NULL    NULL    09:00:00.000    18:00:00.000    NULL    NULL
2   2012/11/10  NULL    NULL    NULL    NULL    NULL    09:00:00.000    18:00:00.000

时间似乎跳到下一个日期同一用户的最后一个空列?有没有办法让我从同一个用户的下一个日期的第一列开始按顺序排列它们?

1 个答案:

答案 0 :(得分:4)

您没有指定您正在使用的RDBMS,但您之前使用sql server标记标记了问题,因此我假设这是数据库。

您可以使用SQL Server中的PIVOT函数执行此操作。有两种方法可以执行此操作,无论是对所有值进行硬编码的静态还是在运行时确定值的动态。

静态数据透视:

select *
from 
(
  select [user], convert(varchar(10), date, 111) date,
    right(convert(varchar(50), date, 121), 12) time
    , 'time'+cast(row_number() over(partition by [user], convert(varchar(10), date, 111) order by date) as varchar(10)) rn
  from yourtable
) src
pivot
(
  max(time)
  for rn in (time1, time2, time3, time4)
) piv

请参阅SQL Fiddle with Demo

动态数据透视:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('time'+cast(row_number() over(partition by [user], convert(varchar(10), date, 111) order by date) as varchar(10))) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [user], date,' + @cols + ' from 
             (
                select [user], convert(varchar(10), date, 111) date,
                  right(convert(varchar(50), date, 121), 12) time
                  , ''time''+cast(row_number() over(partition by [user], convert(varchar(10), date, 111) order by date) as varchar(10)) rn
                from yourtable
            ) x
            pivot 
            (
                max(time)
                for rn in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

汇总/ CASE版本:

如果由于某种原因你不想使用PIVOT函数,那么你也可以使用带有CASE语句的聚合函数。

select [user], date,
  max(case when rn = 1 then time end) Time1,
  max(case when rn = 2 then time end) Time2,
  max(case when rn = 3 then time end) Time3,
  max(case when rn = 4 then time end) Time4
from
(
  select [user], convert(varchar(10), date, 111) date,
    right(convert(varchar(50), date, 121), 12) time
    , row_number() over(partition by [user], convert(varchar(10), date, 111) order by date)) rn
  from yourtable
) src
group by [user], date

请参阅SQL Fiddle with Demo

这三个产生相同的结果:

| USER |       DATE |        TIME1 |        TIME2 |        TIME3 |        TIME4 |
---------------------------------------------------------------------------------
|  001 | 2012/12/01 | 09:00:00.000 | 11:00:00.000 | 12:00:00.000 | 13:00:00.000 |
|  001 | 2012/12/02 | 09:00:00.000 | 11:00:00.000 | 12:00:00.000 | 13:00:00.000 |