获得下一次登录

时间:2012-09-13 01:54:50

标签: sql common-table-expression

我正在尝试根据一系列出勤记录获得正确的登录和注销。这是一个示例数据。

employee_id logdatetime         tkstype
  PH120013  2012-08-25 08:30:00.000 0
  PH120013  2012-08-25 13:00:00.000 1
  PH120013  2012-08-26 02:30:00.000 0
  PH120013  2012-08-27 15:00:00.000 1
  PH120013  2012-08-27 17:00:00.000 0
  PH120013  2012-08-27 21:00:00.000 1
  PH120013  2012-08-28 08:00:00.000 0
  PH120013  2012-08-28 19:00:00.000 1
  PH120013  2012-08-29 03:30:00.000 0
  PH120013  2012-08-29 21:00:00.000 1
  PH120013  2012-08-30 05:30:00.000 0
  PH120013  2012-08-30 19:00:00.000 1
  PH120013  2012-08-31 05:30:00.000 0
  PH120013  2012-08-31 20:30:00.000 1
  PH120013  2012-09-01 01:00:00.000 1
  PH120013  2012-09-01 21:00:00.000 0

TKSTYPE = 0 - IN 1 - OUT

我的困境是根据用户查询日期获取下一次登录。这样我就可以正确注销用户。例如,我想查看用户PH120013的登录信息,日期是2012-08-26。我想要的输出是:

          IN                              OUT

PH120013 2012-08-26 02:30:00.000 2012-08-27 15:00:00.000

这是我的完整查询:

;With Attendance_CTE As 
(

        SELECT employee_id,CONVERT(VARCHAR(10), logdatetime, 120) logdate,
               CONVERT(VARCHAR(12), logdatetime, 114) logtime,logdatetime,tkstype
        FROM MSTR_ATTENDANCE WHERE CONVERT(VARCHAR(10), logdatetime, 120) >='2012-08-26'

),
Employee_CTE As
(
    SELECT employee_id,
       '2012-08-26' + CONVERT(datetime,tks_ofc_in,108) as Official_IN, 
       '2012-08-26' + CONVERT(datetime,tks_ofc_out,108) as Official_OUT,
       hireddate + '00:00:00.000' as HiredDate_DateTime,           
       '2012-08-26' + ' 00:00:00.000' as TKS_DateTime
    FROM vwu_Employee_Contract_Info                 
),
Min_Max_Attendance As
(
    SELECT t_in.employee_id,
           min(isnull(t_in.logdatetime,'1753-01-01 00:00:00.000')) min_in,
           max(isnull(t_out.logdatetime,'1753-01-01 00:00:00.000')) max_out 
    FROM
        (SELECT employee_id,logdatetime FROM Mstr_Attendance WHERE tkstype=0) t_in
    LEFT JOIN   
        (SELECT employee_id,logdatetime FROM Mstr_Attendance WHERE tkstype=1) t_out
    ON
        t_in.employee_id=t_out.employee_id      
    GROUP BY
        t_in.employee_id
)
SELECT Attendance_CTE.Employee_ID,logdatetime,
       CASE WHEN TKSType=0 THEN
           CASE Min_Max_Attendance.min_in 
                -- first day
                WHEN '1753-01-01 00:00:00.000' THEN 
                    CASE
                        -- check if current logdatetime is within the hireddate and current date query
                        WHEN Attendance_CTE.LogDateTime BETWEEN HiredDate_DateTime AND TKS_DateTime 
                        THEN 
                            CASE
                                WHEN Attendance_CTE.LogDateTime BETWEEN Employee_CTE.Official_In AND 
                                     Employee_CTE.Official_Out THEN Attendance_CTE.LogDateTime                                                                                                                           
                            END 
                        ELSE
                        -- no time in?
                                '1753-01-01 00:00:00.000'
                    END
                ELSE
                    -- regular days
                    CASE
                        -- check whether no out
                        WHEN Min_Max_Attendance.max_out = '1753-01-01 00:00:00.000' THEN Attendance_CTE.Logdatetime
                    ELSE
                        -- but with previous out
                        CASE
                            -- check whether logdatetime is not greater than the TKS_DateTime
                            WHEN  Convert(varchar(10),Attendance_CTE.logdatetime,120) !> TKS_DateTime THEN                              
                                  CASE
                                    -- when logdatetime range on employee official time including late
                                    WHEN Attendance_CTE.logdatetime BETWEEN Employee_CTE.Official_In AND Employee_CTE.Official_Out THEN Attendance_CTE.Logdatetime
                                    -- when logdatetime is less than the max l_out on the records
                                    WHEN Attendance_CTE.LogDateTime <= Min_Max_Attendance.max_out THEN Attendance_CTE.LogDateTime
                                    -- when logdatetime is on range between the min l_in and max l_out on the records
                                    WHEN Attendance_CTE.LogDateTime BETWEEN Min_Max_Attendance.min_in AND Min_Max_Attendance.max_out THEN Attendance_CTE.LogDateTime
                                    -- when logdatetime is on range between current query date to official in 
                                    WHEN Attendance_CTE.LogDateTime BETWEEN TKS_DateTime AND Employee_CTE.Official_In THEN Attendance_CTE.LogDateTime                                   
                                    -- when logdatetime is not greater than equal to current query date 
                                    WHEN Attendance_CTE.LogDateTime < TKS_DateTime THEN Attendance_CTE.LogDateTime
                                  END
                            /*ELSE
                                -- no time in?
                                '1753-01-01 00:00:00.000'*/
                        END 
                    END
            END 
        END ActualLogIn,
        CASE WHEN TKSType=1 THEN                 
             CASE
                -- check whether logdatetime is less than  official_out and greater than official_in, undertime
                WHEN Attendance_CTE.LogDateTime > Employee_CTE.Official_Out AND Attendance_CTE.LogDateTime !> Employee_CTE.Official_In
                THEN    Attendance_CTE.LogDateTime
                -- logdatetime is greater than official out and not greater than the next log in                                    
                WHEN Attendance_CTE.LogDateTime >= Employee_CTE.Official_Out AND Attendance_CTE.LogDateTime !> '2012-08-27 17:00:00.000'
                    THEN Attendance_CTE.LogDateTime                         
                WHEN Attendance_CTE.LogDateTime !> '2012-08-27 17:00:00.000'
                THEN Attendance_CTE.LogDateTime                     
             END
        END ActualLogOut            
FROM Employee_CTE
LEFT JOIN Attendance_CTE
ON
    Employee_CTE.Employee_ID=Attendance_CTE.Employee_ID
LEFT JOIN Min_Max_Attendance
ON
    Employee_CTE.Employee_ID=Min_Max_Attendance.Employee_ID
AND
    Attendance_CTE.Employee_ID=Min_Max_Attendance.Employee_ID
WHERE 
    Employee_CTE.Employee_ID IN ('PH120012','PH120013')
  • 2012-08-27 17:00:00.000'&lt; - 硬编码,这是我需要正确使用的

1 个答案:

答案 0 :(得分:2)

试试这个:

由于我不确定数据库,这是一个通用的解决方案,这几乎适用于所有数据库

select * from (
select logi_in.logdatetime as 'IN' , logi_out.logdatetime as 'OUT' 
from MSTR_ATTENDANCE logi_in
left outer join MSTR_ATTENDANCE logi_out
on logi_in.employee_id=logi_out.employee_id
and logi_in.tkstype=0
and logi_out.logdatetime =(
select     MIN(logdatetime)  
             from       MSTR_ATTENDANCE MSTR   
             where      MSTR.employee_id = logi_out.employee_id  
             and        MSTR.tkstype = 1
             and        MSTR.logdatetime > logi_in.logdatetime 
       )
and logi_in.employee_id='PH120013'
and logi_in.logdatetime='2012-08-26 02:30:00.000')t
where OUT is not null


SQL Fiddle demo