如何计算员工工资计算中的第一个班次和最后一个班次?

时间:2014-11-15 06:43:30

标签: sql-server

select employeeid, in_out,ondate
from emp_reporting
where employeeid = 121


employeeid  in_out  ondate
121          IN     2014-11-14 20:00:00.000
121          OUT    2014-11-13 15:15:00.000
121          IN     2014-11-13 20:24:00.000
121          OUT    2014-11-14 06:24:00.000
121          IN     2014-11-14 14:21:00.000
121          OUT    2014-11-14 14:22:00.000

我需要在首次登录时获得上述结果&最后一次注销转移明智,如10:00AM TO 6:00PM06:00AM TO 2:00PM以及02:00PM TO 10:00PM

如何编写此类查询?

3 个答案:

答案 0 :(得分:0)

DECLARE @T1 TABLE(EID INT,in_out VARCHAR(10),ondate DATETIME)
INSERT INTO @T1(EID,in_out,ondate) VALUES
(121,'IN','2014-11-14 20:00:00.000'),
(121,'OUT','2014-11-13 15:15:00.000'),
(121,'IN','2014-11-13 20:24:00.000'),
(121,'OUT','2014-11-14 06:24:00.000'),
(121,'IN','2014-11-14 14:21:00.000'),
(121,'OUT','2014-11-14 14:22:00.000')

SELECT EID,CONVERT(VARCHAR,ondate,106) AS OnDate,
RIGHT(CONVERT(VARCHAR, MIN(ondate), 100),7)+'-'+RIGHT(CONVERT(VARCHAR, MAX(ondate), 100),7) AS TIME 
FROM @T1
GROUP BY EID,CONVERT(VARCHAR,ondate,106)

结果

EID    OnDate            TIME
121  13 Nov 2014     3:15PM- 8:24PM
121  14 Nov 2014     6:24AM- 8:00PM

OR

SELECT ISNULL(a.EID,b.EID)AS EID,ISNULL(CONVERT(VARCHAR, a.ondate, 106),'_')+'-'+ISNULL(CONVERT(VARCHAR, b.ondate, 106),'_')AS Ondate,ISNULL(RIGHT(CONVERT(VARCHAR, a.ondate, 100),7),'_') + ' - ' +ISNULL(RIGHT(CONVERT(VARCHAR, b.ondate, 100),7),'_') AS [Time]  FROM 
(SELECT ROW_NUMBER()OVER(ORDER BY ondate)AS ID,EID,ondate FROM @T1 WHERE in_out='IN' )a FULL JOIN  
(SELECT ROW_NUMBER()OVER(ORDER BY ondate) AS ID,EID,ondate FROM @T1 WHERE in_out='OUT' )b ON a.EID=b.EID AND a.ondate<b.ondate

结果

EID   Ondate                        Time
 121    _-13 Nov 2014                _ -  3:15PM
 121    13 Nov 2014-14 Nov 2014     8:24PM -  6:24AM
 121    13 Nov 2014-14 Nov 2014     8:24PM -  2:22PM
 121    14 Nov 2014-14 Nov 2014     2:21PM -  2:22PM
 121    14 Nov 2014-_               8:00PM - _

答案 1 :(得分:0)

由于我们无法保证每个人都有相应的出局,我们必须要有点防守:

with ordered_punches as (
   select *,
      row_number() over (partition by employeeid, in_out order by outdate) as [n],
      row_number() over (partition by employeeid, in_out order by outdate desc) as [x],
   from emp_reporting
)
select *
from ordered_punches
where in_out = 'IN'
   and n = 1 --the earliest "IN" row

union all

select *
from ordered_punches
where in_out = 'OUT'
   and x = 1 --the latest "OUT" row

如果输入和输出需要在输出的同一行中,我将它作为练习留给读者。

答案 2 :(得分:0)

我理解你的目标 - 在同一行显示工作班次的开始和结束时间 下一个查询将执行此操作,如果错过了一些工作时间戳,将显示NULL

DECLARE @EmpID INT = 121

SELECT CASE WHEN inw.EmployeeId IS NULL THEN 
                 outw.EmployeeId ELSE inw.EmployeeId END AS EmployeeID
, inw.OnDate AS 'Started'
, outw.OnDate AS 'Finished'
, ISNULL(CONVERT(VARCHAR, inw.OnDate, 0), 'n/a')
+ ' - ' + 
ISNULL(CONVERT(VARCHAR, outw.OnDate, 0), 'n/a') AS 'WorkShift'
FROM (
    SELECT w.EmployeeID
    , w.OnDate
    , (SELECT MIN(OnDate)
        FROM Worktime
        WHERE EmployeeId = w.EmployeeId 
        AND In_Out = 'OUT' 
        AND OnDate >w.OnDate) AS 'Finished'
    FROM Worktime w
    WHERE w.EmployeeId = @EmpID AND w.In_Out = 'IN') inw
FULL OUTER JOIN (
    SELECT w.EmployeeID
    , w.OnDate
    , (SELECT MAX(OnDate)
        FROM Worktime
        WHERE EmployeeId = w.EmployeeId 
        AND In_Out = 'IN' 
        AND OnDate < w.OnDate) AS 'Started'
    FROM Worktime w
    WHERE w.EmployeeId = @EmpID AND w.In_Out = 'OUT') outw 
    ON outw.EmployeeId = inw.EmployeeId AND outw.Started = inw.OnDate 
ORDER BY Started

SQL Fiddle example