SQL Server时间表计算

时间:2016-10-25 14:47:51

标签: sql-server tsql datetime sql-server-2012

我有一个时间打孔程序输出下面的数据集。 RECTYP_43是(1)in和(2)out punches。我需要一个查询来查看LOGINDATE_43LOGINTIME_43以及RECTYPE_43的外观,并获得1到2之间的差异。

我认为这比事实证明的要容易。

empid_43    RECTYPE_43  LOGINDATE_43            LOGINTIME_43
------------------------------------------------------------
127            1        2016-10-21 00:00:00.000     0558
127            2        2016-10-21 00:00:00.000     1430
127            2        2016-10-21 00:00:00.000     1201
127            1        2016-10-21 00:00:00.000     1228
127            1        2016-10-24 00:00:00.000     0557
127            2        2016-10-24 00:00:00.000     1200
127            1        2016-10-24 00:00:00.000     1228
127            2        2016-10-24 00:00:00.000     1430
2589           2        2016-10-21 00:00:00.000     1431
2589           1        2016-10-21 00:00:00.000     0556
2589           1        2016-10-24 00:00:00.000     0550
2589           2        2016-10-24 00:00:00.000     1431
2589           2        2016-10-24 00:00:00.000     1201
2589           1        2016-10-24 00:00:00.000     1226
69             1        2016-10-24 00:00:00.000     1229
69             2        2016-10-24 00:00:00.000     1430
69             1        2016-10-24 00:00:00.000     0555
69             2        2016-10-24 00:00:00.000     1200

3 个答案:

答案 0 :(得分:0)

您可以使用CTE获取所有插入信息,然后使用子查询来查找在此之后发生的第一次打卡...

;WITH ctePunchIn AS (
    SELECT empid_43, LOGINDATE_43 AS Date_In, LOGINTIME_43 AS Time_In 
    FROM #Table1 
    WHERE [RECTYPE_43] = 1
 )

 SELECT 
    empid_43, Date_In, Time_In 
    ,(SELECT TOP 1 LOGINTIME_43 FROM #Table1 WHERE 
        (empid_43 = ctePunchIn.empid_43) 
        AND 
        (LOGINDATE_43 = ctePunchIn.Date_In)
        AND 
        (LOGINTIME_43 > ctePunchIn.Time_In) 
        AND 
        (RECTYPE_43 = 2) 
        ORDER BY empid_43, Date_In, LOGINTIME_43) AS Time_Out
FROM 
    ctePunchIn

答案 1 :(得分:0)

如果注销时间与登录时间相同,则Dazedandconfused answer可以正常工作,但如果用户在登录时间的另一天注销,则无效。

e.g。

INSERT into Punch (empId_43, RecType_43, LoginDate_43, LoginTime_43)
VALUES (15, 1, '2016-01-01', '2305'),
(15, 2, '2016-01-02', '0005');

为了适应这种情况,您需要知道该员工的表中的下一项是什么。有了它,您可以确保下一个项目也是一个注销事件。这将有助于捕捉有人忘记冲出的情况。

扩展CTE可以提供更完整的解决方案:

WITH Data AS
(
    SELECT  empId_43,
            RecType_43,
            LoginDate_43,
            LoginTime_43,
            RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43 
                                  ORDER BY LoginDate_43, LoginTime_43)
    FROM Punch
)
SELECT  PIn.empId_43 [Employee],
        PIn.LoginDate_43 [LoginDate],
        PIn.LoginTime_43 [LoginTime],
        POut.LoginDate_43 [LogoutDate],
        POut.LoginTime_43 [LogoutTime]
FROM Data PIn
    LEFT JOIN Data POut ON PIn.empId_43 = POut.empId_43
        AND POut.RecType_43 = 2
        AND POut.RowNum = PIn.RowNum + 1
WHERE PIn.RecType_43 = 1
ORDER BY PIn.empId_43, PIn.LoginDate_43, PIn.LoginTime_43;

但是,Row_Number 可能效率低下。在查看一个小子集(例如特定日期范围等)时,最好这样做。

答案 2 :(得分:0)

采用略有不同的方式:

select
   punchIn.empid_43,
   punchIn.login as dateTime_in,
   punchout.login as dateTime_out
from
(
    SELECT  empId_43,
            RecType_43,
            LoginDate_43,
            LoginTime_43,
            dateadd('n',right(logintime_43,2),
            dateadd('hh',left(LoginTime_43,2), 
            LoginDate_43)) as login,
            RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43 
                                  ORDER BY LoginDate_43, LoginTime_43)
    FROM Punch
where rectype_43 = 1
) punchIn left outer join 
(
    SELECT  empId_43,
            RecType_43,
            LoginDate_43,
            LoginTime_43,
            dateadd('n',right(logintime_43,2),
            dateadd('hh',left(LoginTime_43,2), 
            LoginDate_43)) as login,
            RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43 
                                  ORDER BY LoginDate_43, LoginTime_43)
    FROM Punch
where rectype_43 = 2
) punchOut on
punchin.empID = punchout.empID and
punchin.rownum = punchout.rownum

假设所有打孔行都有相应的打孔行