SQL Server:根据另一列

时间:2015-08-06 10:25:08

标签: sql-server tsql

我有一张表Access

logId   empid   empname  inout   tim  
----------------------------------------------------    
230361   0100     XYZ     0      2015-08-01 10:00:03
230362   0106     XYZ     0      2015-08-01 10:30:00
230363   0100     XYZ     1      2015-08-01 12:00:00

记录每位员工的及时和时间。 inout=0表示在inout=1表示

我想从此表中创建如下表格

empid  empname     timIn                 timOut
-------------------------------------------------------------    
0100     XYZ       2015-08-01 10:00:03   2015-08-01 12:00:00
0106     XYZ       2015-08-01 10:30:00

首先,我尝试了以下案例:

select 
    empid, empname, inout,
    case when inout = 0 then tim end as 'timIn',
    case when inout = 1 then tim end as 'timout'

但是NULL结果是

的问题
0100  xyz       2015-08-01 10:00:03   NULL
0100  xyz       NULL                  2015-08-01 12:00:00

其次我试过PIVOT,但问题是我必须使用聚合函数。我需要所有的进出时间,不能总结。

有没有其他方法可以获得所需的结果?

3 个答案:

答案 0 :(得分:3)

您可以将APPLYTOP 1和正确的ORDER BY结合使用,以便在事件发生后获得下一个事件

SELECT  i.empID,
        i.empname,
        TimeIn = i.tim,
        TimeOut = o.tim
FROM    Access AS i
        OUTER APPLY
        (   SELECT  TOP 1 tim
            FROM    Access AS o
            WHERE   o.EmpID = i.EmpID
            AND     o.InOut = 1
            AND     o.tim > i.tim
            ORDER BY o.Tim
        ) AS o
WHERE   i.InOut = 0;

因此,您只需选择所有in个事件(表别名i),然后针对每个in事件,找到下一个out事件,如果没有,那么超时字段将为空。

完整的工作示例

DECLARE @Access TABLE (LogID INT NOT NULL, EmpID CHAR(4) NOT NULL, empname VARCHAR(50), InOut BIT NOT NULL, tim DATETIME2 NOT NULL);
INSERT @Access (LogID, EmpID, empname, InOut, tim)
VALUES
    (230361, '0100', 'XYZ', 0, '2015-08-01 10:00:03'),
    (230362, '0106', 'XYZ', 0, '2015-08-01 10:30:00'),
    (230363, '0100', 'XYZ', 1, '2015-08-01 12:00:00');

SELECT  i.empID,
        i.empname,
        TimeIn = i.tim,
        TimeOut = o.tim
FROM    @Access AS i
        OUTER APPLY
        (   SELECT  TOP 1 tim
            FROM    @Access AS o
            WHERE   o.EmpID = i.EmpID
            AND     o.InOut = 1
            AND     o.tim > i.tim
            ORDER BY o.Tim
        ) AS o
WHERE   i.InOut = 0;

答案 1 :(得分:1)

更新:根据评论,我应该改进此查询以获取所有日期数据,而不仅仅是上次日期的数据,更新后的查询只包含新的日期列

select empid,empname,d,[0] as [timin],[1] as [timOut]
from
(select empid,empname, cast(tim as DATE)as d,inout,tim from tbl) s
pivot
(max(tim) for inout in ([0],[1]))p

更新了小提琴链接http://sqlfiddle.com/#!6/f1bc7/1

  

尝试PIVOT这样的查询:

select empid,empname,[0] as [timin],[1] as [timOut]
from
(select empid,empname,inout,tim from tbl) s
pivot
(max(tim) for inout in ([0],[1]))p
     

添加了SQL小提琴链接http://sqlfiddle.com/#!6/6c3bf/1

答案 2 :(得分:1)

所以我认为你想做的是每次进入后第一次找到。下面的SQL应该这样做。

Select 
empid,
empname,
tim as timein 
(select top 1 tim 
 from my_table outTimes 
 where outTimes.inout = 1 and 
       outTimes.empid = inTimes.empid and 
       outTimes.tim > inTimes.tim 
 orderby outTimes.tim asc
) as timeout
from my_table inTimes
when inout=0

这里的关键位是orderby asc和top 1.这是下一次在桌面上给你的东西。