2

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

登录表的示例数据是

 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 101SignIn时间但no SignOut

SQLFiddle用于生成表数据

4

2 回答 2

4

您使用该PIVOT功能走在正确的轨道上,您只需要一种row_number()基于和/ 为每一行分配 a 的方法empid,您可以使用以下代码:statusdatepivot

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 fiddle 的@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) |
于 2013-03-07T11:02:03.313 回答
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,为此我将用户添加了EmpID102 到示例数据。

于 2013-03-07T06:54:27.143 回答