SQL服务器获取不领先或滞后的结束日期记录的开始日期

时间:2017-06-18 16:23:22

标签: sql sql-server

我有一个指纹系统 它有几列 用户,设备,模式,活动时间

用户是员工 该设备是2个设备,一个是室外的外部人员,一个是室内的内部人员 包含多种模式的活动 F1:保留\。参加 F2:中断 F3:工作假 F4:个人休假 F5:吸烟休假

    CREATE TABLE dbo.UserActivity (
 [User] int NOT NULL,
 Mode varchar(6) NOT NULL,
 Activity varchar(6) NOT NULL,
 ActivityTime datetime NOT NULL
) 
GO

--Insert data into the UserActivity table
INSERT dbo.UserActivity ([User] ,Mode , Activity, ActivityTime) 
VALUES (1,'F1' ,'Divout', CAST('2013-01-01 08:30' AS datetime))
, (1,'F3' ,'Divin', CAST('2013-01-01 10:45' AS datetime))
, (1,'F3' ,'Divout', CAST('2013-01-01 13:15' AS datetime))
, (1,'F5' ,'Divin', CAST('2013-01-01 15:30' AS datetime))
, (1,'F3' ,'Divin', CAST('2013-01-01 16:15' AS datetime))
, (1,'F3' ,'Divout', CAST('2013-01-01 17:00' AS datetime))
, (1,'F1' ,'Divout', CAST('2013-01-02 08:30' AS datetime))
, (1,'F3' ,'Divin', CAST('2013-01-02 10:45' AS datetime))
, (1,'F4' ,'Divout', CAST('2013-01-02 13:00' AS datetime))
, (1,'F1' ,'Divin', CAST('2013-01-02 16:45' AS datetime))
, (2,'F1' ,'Divout', CAST('2013-01-01 8:25' AS datetime))
, (2,'F3' ,'Divin', CAST('2013-01-01 11:30' AS datetime))
, (2,'F3' ,'Divout', CAST('2013-01-01 12:35' AS datetime))
, (2,'F1' ,'Divin', CAST('2013-01-01 14:45' AS datetime))

我很好地订购了每个人在开始和结束时的活动 我也处理了一些错误 1 - 如果相同的设备连续使用两次,那么它的错误“因为当你从里面打印时应该从外面打印” 2-如果启动活动与结束活动不匹配则错误“如果您打印F2模式然后返回则必须打印F2模式”

这是我的代码:

select *,Error_Column=CASE 
                      WHEN ((Lag(T2.Activity, 1)OVER(ORDER BY T2.[UserName],T2.EndActivityTime,T2.CurrentMode)=T2.Activity)--2 finger prints from same device
                       or ((T2.PreviousMode<>T2.CurrentMode) and (T2.PreviousMode is not null or T2.CurrentMode is not Null)))--inside mode differenet than outside mode
                      then 1
                      else 0
                      end
 from (

SELECT Activity --Device Place
,CurrentMode=Mode --Device Mode
, PreviousMode = --Inter F
     CASE 
     WHEN Activity='Divout' --UserName was out and he return
     THEN  Lag([Mode], 1) OVER(ORDER BY [User],ActivityTime,Mode) --give me his last leave state
     Else Null --Else UserName using inside so we don't need his last leave state
     End
, ActivityDate = CAST(ActivityTime As DATE) --Date of Activity
, UserName = [User] --UserName
, EndActivityTime = ActivityTime
, StartActivityTime = 
    CASE 
    WHEN Activity='Divout' --UserName was out and he return
    THEN Lag(ActivityTime, 1) OVER(ORDER BY [User], ActivityTime,Mode)
     Else Null
     End
, EndActivityDate = CAST(ActivityTime AS DATE)
, StartActivityDate = 
    CASE 
    WHEN Activity='Divout' --UserName was out and he return
    Then CAST(Lag(ActivityTime, 1) OVER(ORDER BY [User], ActivityTime ,Mode) AS DATE)
     Else Null
     End
FROM dbo.UserActivity
where mode<>'F1'

Union 

SELECT Activity --Device Place
,CurrentMode=Mode --Device Mode
, PreviousMode = --Inter F
     CASE 
     WHEN Activity='Divin' --End of the Day
     THEN  Lag([Mode], 1) OVER(ORDER BY [User],ActivityTime,Mode) --give me his Attendance Mode
     Else Null --Else UserName using outside so we don't need his last leave state
     End
, ActivityDate = CAST(ActivityTime As DATE) --Date of Activity
, UserName = [User] --UserName
, EndActivityTime = ActivityTime
, StartActivityTime = 
    CASE 
    WHEN Activity='Divin' 
    THEN Lag(ActivityTime, 1) OVER(ORDER BY [User], ActivityTime,Mode)
     Else Null
     End
, EndActivityDate = CAST(ActivityTime AS DATE)
, StartActivityDate = 
    CASE 
    WHEN Activity='Divin' 
    Then CAST(Lag(ActivityTime, 1) OVER(ORDER BY [User], ActivityTime,Mode) AS DATE)
     Else Null
     End
FROM (select * from  dbo.UserActivity where mode='F1') T1)T2
ORDER BY T2.[UserName],T2.EndActivityTime,T2.CurrentMode

我遇到的问题是有一些特殊情况我无法找到处理方法 例如。当你是“F3:工作假”时......你可能不会重返工作岗位 在这种情况下,F1将被F3关闭..也有时您可能会在工作日结束前用1小时休假。所以你会打印F4 在这种情况下,F1将被F4关闭。

我想了很多我应该如何处理我的代码中的这两个案例,但我无法找到解决方案

任何人都可以帮我处理它们...... 提前谢谢

1 个答案:

答案 0 :(得分:0)

我建议您在逻辑中使用 PARTITION BY 。例如:

select
    *
from (
    select
          CAST(ActivityTime AS date) act_date
        , row_number() over(partition by [User], CAST(ActivityTime AS date)
                            order by ActivityTime ASC)                     start_row
        , row_number() over(partition by [User], CAST(ActivityTime AS date)
                            order by ActivityTime DESC)                    end_row
        , [User]
        , Mode
        , Activity
        , ActivityTime
    from UserActivity
    ) d
order by act_date, [User], start_row
;
     

在start_row 1和end_row 1之间,您可以看到每个用户每天的完整活动顺序。我认为,一旦建立了这些边界,它将使您更容易应用业务逻辑。

act_date   | start_row | end_row | User | Mode | Activity | ActivityTime       
:----------|-----------|-------- | -----|------|----------|--------------------
01/01/2013 | 1         | 6       |    1 | F1   | Divout   | 01/01/2013 08:30:00
01/01/2013 | 2         | 5       |    1 | F3   | Divin    | 01/01/2013 10:45:00
01/01/2013 | 3         | 4       |    1 | F3   | Divout   | 01/01/2013 13:15:00
01/01/2013 | 4         | 3       |    1 | F5   | Divin    | 01/01/2013 15:30:00
01/01/2013 | 5         | 2       |    1 | F3   | Divin    | 01/01/2013 16:15:00
01/01/2013 | 6         | 1       |    1 | F3   | Divout   | 01/01/2013 17:00:00

01/01/2013 | 1         | 4       |    2 | F1   | Divout   | 01/01/2013 08:25:00
01/01/2013 | 2         | 3       |    2 | F3   | Divin    | 01/01/2013 11:30:00
01/01/2013 | 3         | 2       |    2 | F3   | Divout   | 01/01/2013 12:35:00
01/01/2013 | 4         | 1       |    2 | F1   | Divin    | 01/01/2013 14:45:00

02/01/2013 | 1         | 4       |    1 | F1   | Divout   | 02/01/2013 08:30:00
02/01/2013 | 2         | 3       |    1 | F3   | Divin    | 02/01/2013 10:45:00
02/01/2013 | 3         | 2       |    1 | F4   | Divout   | 02/01/2013 13:00:00
02/01/2013 | 4         | 1       |    1 | F1   | Divin    | 02/01/2013 16:45:00

dbfiddle here