在SQL中用Pivot一天选择Times

时间:2014-06-04 07:37:34

标签: sql-server pivot

我有一张桌子:

CREATE TABLE [PersonelTraffic](
    [CardNo] [int] ,
    [CardDateTime] [smalldatetime] )

和行为:

CardNo  CardDateTime
1048    2014-06-02 16:30:00
1414    2014-06-02 13:11:00
1414    2014-06-02 13:59:00
1414    2014-06-02 16:43:00

如何选择按天显示一行的时间:

CardNo  Date         Time0    Time1    Time2   Time3
1414    2014-06-02   13:11    13:59    16:43   Null
1048    2014-06-02   16:30    Null     Null    Null

使用Pivot运算符或任何其他解决方案。

3 个答案:

答案 0 :(得分:1)

MayBe像这样的东西

;with cte as
(
  SELECT CardNo,CardDateTime,Cast(CardDateTime As Date)AS Date,Row_Number() over(Partition By CARDNO Order By CARDNO) AS RN
  FROM personeltraffic
)    
SELECT CardNo,Date,
       MAX(CASE WHEN RN = 1 Then Convert(char(5), CardDateTime, 108) ELSE NULL End)AS Time1,
       MAX(CASE WHEN RN = 2 Then Convert(char(5), CardDateTime, 108) ELSE NULL End)AS Time2,
       MAX(CASE WHEN RN = 3 Then Convert(char(5), CardDateTime, 108) ELSE NULL End)AS Time3,
       MAX(CASE WHEN RN = 4 Then Convert(char(5), CardDateTime, 108) ELSE NULL End)AS Time4
From cte
Group By CardNo,Date

SQL FIDDLE DEMO


<强>输出:

+--------+------------+---------+---------+---------+--------+
| CardNo | Date       |  Time0  |  Time1  |  Time2  | Time3  |
+--------+------------+---------+---------+---------+--------+
| 1414   | 2014-06-02 |  13:11  |  13:59  |  16:43  | Null   |
| 1048   | 2014-06-02 |  16:30  |  Null   |  Null   | Null   |
+--------+------------+---------+---------+---------+--------+

答案 1 :(得分:0)

您可以这样做:

;with cte as
(select cardno, convert(time,carddatetime) cardtime, row_number() over (partition by cardno order by carddatetime) rn
from personeltraffic)

select distinct p.cardno [CardNo], 
convert(date,p.carddatetime) [Date], 
c1.cardtime [Time0], 
c2.cardtime [Time1], 
c3.cardtime [Time2], 
c4.cardtime [Time3]
from personeltraffic p
left join cte c1 on p.cardno = c1.cardno and c1.rn = 1
left join cte c2 on p.cardno = c2.cardno and c2.rn = 2
left join cte c3 on p.cardno = c3.cardno and c3.rn = 3
left join cte c4 on p.cardno = c4.cardno and c4.rn = 4 
order by p.cardno

基本上,您使用row_number()为一天内的每个时间分配一个序列号,然后多次连接以获得序列中特定数字的时间。但是,考虑到此查询中的连接数,我建议您出于性能原因寻找替代方案。

答案 2 :(得分:0)

除Vignesh Kumar的答案外,基于PIVOT的答案基本上使用相同的执行计划:

SELECT
    CardNo,
    [Date],
    CONVERT(CHAR(5), [1], 108) AS [Time0],
    CONVERT(CHAR(5), [2], 108) AS [Time1],
    CONVERT(CHAR(5), [3], 108) AS [Time2],
    CONVERT(CHAR(5), [4], 108) AS [Time3]
FROM (
    SELECT
        CardNo,
        CONVERT(DATE, CardDateTime) AS [Date],
        CardDateTime,
        ROW_NUMBER() OVER (PARTITION BY CardNo ORDER BY CardDateTime) AS TimeOrdinal
    FROM
        PersonelTraffic
) pt
PIVOT (
    MAX(CardDateTime) FOR [TimeOrdinal] IN (
        [1],
        [2],
        [3],
        [4]
    )
) pvt