Sql 从行编号中选择连续行

Sql 从行编号中选择连续行,sql,sql-server,row-number,Sql,Sql Server,Row Number,我正在从一个工资系统的SQL Server数据库中提取数据 我有以下疑问: ;WITH emp AS ( SELECT [USER_ID], [LOG_TIME], CAST([LOG_TIME] AS DATE) AS [PunchDate], [DEVICE_SERIAL_NO], [AUTHORIZE_REASON_CODE], [STRINGCLOCKING_TYPE0],

我正在从一个工资系统的SQL Server数据库中提取数据

我有以下疑问:

;WITH emp AS
(
    SELECT 
        [USER_ID],
        [LOG_TIME],
        CAST([LOG_TIME] AS DATE)  AS [PunchDate],
        [DEVICE_SERIAL_NO],
        [AUTHORIZE_REASON_CODE],
        [STRINGCLOCKING_TYPE0],
        ROW_NUMBER() OVER (PARTITION BY [USER_ID], CAST([LOG_TIME] AS DATE)
                           ORDER BY [USER_ID], [LOG_TIME]) AS [RowNumber]
    FROM 
        [SekureTime].dbo.USER_TIME_LOG 
    WHERE 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [DEVICE_SERIAL_NO] = '34007965' 
         AND [AUTHORIZE_REASON_CODE] = 'Access')
        OR 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [EDIT_USER] = '4' 
         AND [CLOCKING_TYPE0] = '11') 
        OR 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [EDIT_USER] = '4'
         AND [CLOCKING_TYPE0] = '8')
)
SELECT 
    t1.[USER_ID] AS [EMPID],
    t1.[PunchDate],
    t1.[DEVICE_SERIAL_NO],
    t1.[AUTHORIZE_REASON_CODE],
    t1.[STRINGCLOCKING_TYPE0],
    CONVERT(TIME(0), MIN(t1.[LOG_TIME]))  AS [punch1],
    CONVERT(TIME(0), MAX(t2.[LOG_TIME])) AS [punch2],
    SUM(ISNULL(DATEDIFF(MI, t1.[LOG_TIME], t2.[LOG_TIME]), 0)) AS [TotalMinutes]
FROM  
    emp AS t1
LEFT JOIN 
    emp AS t2 ON (t1.[USER_ID] = t2.[USER_ID]
                  AND t1.[PunchDate] = t2.[PunchDate]
                  AND t1.[RowNumber] = (t2.[RowNumber] - 1)
                  AND t2.[RowNumber] % 2 = 0)
GROUP BY 
    t1.[USER_ID],
    t1.[PunchDate],
    t1.[DEVICE_SERIAL_NO],
    t1.[AUTHORIZE_REASON_CODE],
    t1.[STRINGCLOCKING_TYPE0]
如果我让员工一天只打2次拳,但有些员工实际上打了4次拳(午餐打卡,午餐打卡)

我怎么能从那些日子里得到四拳?而不仅仅是第一个(最小值)和最后一个(最大值)

预期结果应该是:

Punch Date  Emp Number  PunchDetail In      Out
9/5/2020    30919       47590       10:00 AM    7:30 PM
9/6/2020    32246       47591       10:45 AM    7:00 PM
9/6/2020    34015       47592       10:30 AM    7:00 PM
9/6/2020    34334       47593       10:15 AM    2:15 PM  <--
9/6/2020    34334       47594        2:55 AM    7:15 PM  <--
9/7/2020    34350       47595       10:30 AM    7:00 PM
9/7/2020    34792       47596       10:30 AM    7:15 PM
打孔日期Emp编号打孔详情输入输出
2020年9月5日30919 47590上午10:00下午7:30
2020年9月6日3224647591上午10:45下午7:00
2020年9月6日34015 47592上午10:30下午7:00

2020年9月6日34334 47593上午10:15下午2:15作为10人的天真开端,做出以下假设:

  • 第一个日志永远不会注销
  • 冲头总是成对显示
  • 如果有人登录但未退出,请忽略该日志

而不是连接,只是聚合和用例语句

;WITH emp AS
(
    SELECT 
        [USER_ID],
        [LOG_TIME],
        CAST([LOG_TIME] AS DATE)  AS [PunchDate],
        [DEVICE_SERIAL_NO],
        [AUTHORIZE_REASON_CODE],
        [STRINGCLOCKING_TYPE0],
        ROW_NUMBER() OVER (PARTITION BY [USER_ID], CAST([LOG_TIME] AS DATE)
                           ORDER BY [USER_ID], [LOG_TIME]) AS [RowNumber]
    FROM 
        [SekureTime].dbo.USER_TIME_LOG 
    WHERE 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [DEVICE_SERIAL_NO] = '34007965' 
         AND [AUTHORIZE_REASON_CODE] = 'Access')
        OR 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [EDIT_USER] = '4' 
         AND [CLOCKING_TYPE0] = '11') 
        OR 
        ([LOG_TIME] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE() - 31), 0) 
         AND [EDIT_USER] = '4'
         AND [CLOCKING_TYPE0] = '8')
),
    pivotted AS
(
    SELECT 
        emp.[USER_ID] AS [EMPID],
        emp.[PunchDate],
        emp.[DEVICE_SERIAL_NO],
        emp.[AUTHORIZE_REASON_CODE],
        emp.[STRINGCLOCKING_TYPE0],
        CONVERT(TIME(0), MAX(CASE WHEN emp.[RowNumber] % 2 = 1 THEN emp.[LOG_TIME] END))  AS [punch1],
        CONVERT(TIME(0), MAX(CASE WHEN emp.[RowNumber] % 2 = 0 THEN emp.[LOG_TIME] END))  AS [punch2]
    FROM  
        emp
    GROUP BY 
        emp.[USER_ID],
        emp.[PunchDate],
        emp.[DEVICE_SERIAL_NO],
        emp.[AUTHORIZE_REASON_CODE],
        emp.[STRINGCLOCKING_TYPE0],
        (emp.[RowNumber]-1) / 2
)
SELECT
    *,
    ISNULL(DATEDIFF(MI, [punch1], [punch2]), 0)   AS [TotalMinutes]
FROM
    pivotted
分组依据(emp.[RowNumber]-1)/2
由于整数运算,确保所有内容都分组到顺序对中

1  =>  (1-1)/2  =>  0/2  =>  0
2  =>  (2-1)/2  =>  1/2  =>  0
3  =>  (3-1)/2  =>  2/2  =>  1
4  =>  (4-1)/2  =>  3/2  =>  1
5  =>  (5-1)/2  =>  4/2  =>  2

你真的需要把注意力集中在
最基本的
部分:(把你的查询只放在与你遇到困难的问题相关的部分,剩下的部分会让人分心,以至于人们甚至不想尝试)并展示一些示例数据/预期结果。感谢@marc_s整理你的代码,我可能会尝试一下。但是有几个问题。。。如果他们登录而不是退出,您希望为
TotalMinutes
显示什么?或者如果他们在一天中多次登录和注销?它是否都必须放在一行上,或者将每个输入输出对作为它自己的行是可以接受的?“你怎么能确定第一个事件肯定是一个登录,而不是一个通宵工作的人?”MatBailie补充道,预期的结果令人质疑。谢谢,我知道你在那里做什么了,但是你的查询在同一行中显示了4个拳。有没有办法让第二行(同一日期)有第三个和第四个打孔呢?@VinicioGuzman-是的,
groupby(emp.[RowNumber]-1)/2
会把所有东西成对地抽出来。我已经编辑了答案