聚合数据透视表的日期时间列

时间:2013-03-07 06:26:58

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

我有一个存储员工登录信息的表

登录表的示例数据是

 EmpID  Status     [Time]
 100    SignIn    2013-03-07 11:41:44.473
 101    SignIn    2013-03-07 10:41:44.473
 100    SignOut   2013-03-07 12:41:44.473
 101    SignOut   2013-03-07 11:41:44.473
 101    SignIn    2013-03-08 11:41:44.473

我希望结果是

EmpID   SignIn                    SignOut
 100    2013-03-07 11:41:44.473    2013-03-07 12:41:44.473
 101    2013-03-07 10:41:44.473    2013-03-07 11:41:44.473
 101    2013-03-08 11:41:44.473    NULL

我尝试使用PIVOT

Select EmpID,[SignIn],[SignOut]
from 
(Select EmpId,status,LoginTime from Login)p
 pivot
(
 min(Logintime)
 For status in ([SignIn],[SignOut])
)pvt

但上述查询遗漏了Employee 101 SignIn时间no SignOut

的最后一行

SQLFiddle用于生成表格数据

2 个答案:

答案 0 :(得分:3)

你可以这样:

SELECT  l1.EmpID
        , l1.LoginTime [SignIn]
        , l2.LoginTime [SignOut]
FROM    Login l1
LEFT JOIN   
        Login l2 ON 
        l2.EmpID = l1.EmpID
AND     CAST(l2.LoginTime AS DATE) = CAST(l1.LoginTime AS DATE)
AND     l2.status = 'SignOut'
WHERE   l1.status = 'SignIn'

请注意,如果您的员工每天有多次登录/注销,并且您想要获得他的第一个SignIn和最后SignOut一天,则必须更改查询:

SELECT  l1.EmpID
        , MIN(l1.LoginTime) [SignIn]
        , MAX(l2.LoginTime) [SignOut]
FROM    Login l1
LEFT JOIN   
        Login l2 ON 
        l2.EmpID = l1.EmpID
AND     CAST(l2.LoginTime AS DATE) = CAST(l1.LoginTime AS DATE)
AND     l2.status = 'SignOut'
WHERE   l1.status = 'SignIn'
GROUP BY
        l1.EmpID, CAST(l1.LoginTime AS DATE)

这是另一个查询,也适用于同一天用户的多次登录/注销。这将在一天内列出他所有的登录/注销:

;WITH cte1 AS
(
    SELECT  *
            , ROW_NUMBER() OVER 
                (PARTITION BY EmpID, CAST(LoginTime AS DATE) ORDER BY LoginTime) 
                AS num
    FROM    Login
)

SELECT  l1.EmpID
        , l1.LoginTime [SignIn]
        , l2.LoginTime [SignOut]
FROM    cte1 l1
LEFT JOIN   
        cte1 l2 ON 
        l2.EmpID = l1.EmpID
AND     CAST(l2.LoginTime AS DATE) = CAST(l1.LoginTime AS DATE)
AND     l2.num = l1.num + 1
WHERE   l1.status = 'SignIn'

以下是 SQL Fiddle ,用于处理一天内用户的多个登录/注销方案的最后两个查询,为此我添加了EmpID 102的用户样本数据。

答案 1 :(得分:3)

您使用PIVOT功能走在正确的轨道上,您只需要根据row_number()empid和{status为每行分配一个date {1}} /您可以使用以下pivot代码:

Select EmpID,[SignIn],[SignOut]
from 
(
  Select EmpId, status, 
    LoginTime, 
    cast(logintime as date) date,
    row_number() over(partition by empid, status, cast(logintime as date)
                      order by logintime) rn
  from Login
)p
pivot
(
  min(Logintime)
  For status in ([SignIn],[SignOut])
)pvt

请参阅SQL Fiddle with Demo

您会注意到子查询中有两个新列。一个为每行生成row_number(),第二个生成date,没有时间。这两列都在GROUP BY中使用,但未在最终选择中显示。它们被使用,因此您可以每天为每位员工获取多行(如果需要)。

使用来自sql小提琴的@ IvanG数据的结果是:

| EMPID |              SIGNIN |             SIGNOUT |
-----------------------------------------------------
|   100 | 2013-03-07 11:41:44 | 2013-03-07 12:41:44 |
|   101 | 2013-03-07 10:41:44 | 2013-03-07 11:41:44 |
|   101 | 2013-03-08 11:41:44 |              (null) |
|   102 | 2013-04-08 12:41:44 | 2013-04-08 13:41:44 |
|   102 | 2013-04-08 16:41:44 | 2013-04-08 17:41:44 |
|   102 | 2013-04-08 19:41:44 |              (null) |