查找多次滑动之间的总分钟数 In/Swipe Out Timestamps - Select 来自垂直行的多条记录并转换水平行

Find Total Mins Between Multiple Swipe In/Swipe Out Timestamps - Select multiple records from vertical row and transform horizontal row

我正在处理 SQL 服务器查询,以获取将处理多个任务代码的用户列表的徽章退出时间 - 进入时间。

task_mgmt - 表名

Table列如下

Task_Sn 用户名 Task_Code 动作 Badge_IN_OUT_TIME
1 安迪 博客 开始 2021-07-20 08:11:45.000
2 安迪 博客 结束 2021-07-20 10:11:45.000
3 贝基 ACCTS 开始 2021-07-20 11:11:45.000
4 贝基 ACCTS 结束 2021-07-20 12:11:45.000
5 安迪 博客 开始 2021-07-20 12:15:45.000
6 安迪 博客 结束 2021-07-20 12:25:45.000
7 安迪 博客 开始 2021-07-20 12:25:00.000
8 贝基 ACCTS 开始 2021-07-20 13:00:00.000
9 贝基 ACCTS 结束 2021-07-20 13:30:00.000

我排除了结果

用户名 Task_Code Badge_IN_TIME Badge_OUT_TIME TOTAL_MINS_SPENT
安迪 博客 2021-07-20 12:25:55.000 135
贝基 ACCTS 2021-07-20 13:00:00.000 2021-07-20 13:30:00.000 90

我真的想不出任何问题。我是 SQL 的初学者,我知道 CRUD 操作。这对我来说似乎超级复杂。

Select UserName,
       Task_Code,
       Badge_In_Time,
       Badge_Out_Time,
       (Badge_Out_Time - Badge_In_Time) as TOTAL_TIME_SPENT
from task_mgmt
order by Badge_IN_OUT_TIME desc

由于安迪目前正在徽章入场但尚未出场,因此最新的徽章出场时间戳计算为 [getdate() - 徽章入场] LastTransaction 分钟数(5 分钟)

这似乎有效:

SELECT UserName,
       Task_Code,
       task_in.Task_Sn as Task_In_Sn,
       TOUT.Task_Out_Sn,
       task_in.Badge_IN_OUT_TIME as Time_In_Raw,
       FORMAT(task_in.Badge_IN_OUT_TIME, 'hh\:mm') as Task_In_Time,
       FORMAT(TOUT.Task_Out_Time, 'hh\:mm') as Task_Out_Time,
       DATEDIFF(minute, task_in.Badge_IN_OUT_TIME,
                 ISNULL(TOUT.Task_Out_Time, GETDATE())) as LengthOfTime
FROM task_mgmt task_in
    OUTER APPLY (
       SELECT TOP 1
            task_out.Task_Sn as Task_Out_Sn,
            task_out.Badge_IN_OUT_TIME as Task_Out_Time
        FROM task_mgmt task_out
        WHERE task_out.Action = 'END' AND
              task_out.UserName = task_in.UserName AND
              task_out.Task_Sn > task_in.Task_Sn
        ORDER BY Task_Sn
    ) TOUT
WHERE task_in.Action = 'START'
ORDER BY Task_Sn

请注意,OUTER APPLY 查找具有更大 Task_Sn 且符合其他条件的第一条记录(我本可以使用 Badge_IN_OUT_TIME 而不是 Task_Sn,但是整数更好一些,也可能更有效率)。

另请注意 DATEDIFF 中的 ISNULL 在日期为 NULL 时替换 GETDATE

如果需要对多个区间求和,可以使用GROUP BY

我提供了答案,但我知道预期结果中缺少两列。

注意:两列 Badge_IN_TIME Badge_OUT_TIME 丢失了,因为我不确定是什么你想检索这两列,如果你能像你为 TOTAL_TIME_SPENT 显示的那样阐明这些拖列的结果和预期值,我可以编辑问题并添加这两列推导。

将逻辑添加到上述列后,这就是我的查询 returns。我认为预期的答案也有一些问题,应该符合逻辑。

SELECT 
  DISTINCT 
  UserName
  , Task_Code
  ,( SELECT  MAX(Badge_IN_OUT_Time ) from  task_mgmt E where E.UserName =  A.UserName   and A.Task_code =  E.Task_Code and    [Action] ='Start'  )  Badge_IN_TIME
   ,( SELECT  MIN(Badge_IN_OUT_Time ) from  task_mgmt E where E.UserName =  A.UserName   and A.Task_code =  E.Task_Code and    [Action] ='END'  )  Badge_OUT_TIME
  , SUM( [DATEDIFF] ) OVER (PARTITION BY  UserName, Task_Code, [Action]  order by  UserName ) as  Total_MinsSpend
 FROM 
  (
   SELECT 
   Task_sn
 , UserName
 , Task_Code
 , [Action]
 , Badge_IN_OUT_Time 
 , ISNULL( LEAD(Badge_IN_OUT_Time) over  (Partition by UserName, Task_Code order by UserName ), '2021-07-20 12:30:00.000') as [StartTime_Lead]
 ,  DATEDIFF ( MINUTE,Badge_IN_OUT_Time ,iSNULL( LEAD(Badge_IN_OUT_Time) over  (Partition by UserName, Task_Code order by UserName ), '2021-07-20 12:30:00.000')  ) as [DATEDIFF] --Get the date dfference  
  FROM  task_mgmt
  )
 AS A Where A.[Action]  in ('Start')

在您的示例数据中,Andy 的最后开始时间早于他的最后结束时间,因此产生了重叠。鉴于您如何描述计算总分钟数的逻辑,我假设这是不正确的。因此在我的示例中 table 我已经相应地进行了调整。

考虑以下几点:

我使用派生的 table 和 LEAD() 函数来捕获下一个日期和操作的位置。我在外部查询中使用它来根据我的下一步行动确定使用的分钟数。

我使用 CROSS APPLY 来确定用户名和任务的 MAX 开始和结束日期。

CREATE TABLE #tmp(Task_Sn int,  UserName varchar(20),Task_Code varchar(10), Action varchar(10), Badge_IN_OUT_TIME datetime)
INSERT INTO #tmp
VALUES
(1,'Andy','BLOG','START','2021-07-20 08:11:45.000'),
(2,'Andy','BLOG','END','2021-07-20 10:11:45.000'),
(3,'Becky','ACCTS','START','2021-07-20 11:11:45.000'),
(4,'Becky','ACCTS','END','2021-07-20 12:11:45.000'),
(5,'Andy','BLOG','START','2021-07-20 12:15:45.000'),
(6,'Andy','BLOG','END','2021-07-20 12:25:45.000'),
(7,'Andy','BLOG','START','2021-07-20 12:35:00.000'),
(8,'Becky','ACCTS','START','2021-07-20 13:00:00.000'),
(9,'Becky','ACCTS','END','2021-07-20 13:30:00.000')


SELECT X.UserName,X.Task_Code ,Y.ST_TIME Badge_IN_TIME
    ,CASE WHEN Y.ST_TIME > Y.ED_TIME THEN NULL ELSE Y.ED_TIME END Badge_OUT_TIME 
    ,SUM(CASE WHEN Action = 'START' AND NX_ACTION= 'END' THEN DATEDIFF(minute,Badge_IN_OUT_TIME, NX_TIME) 
         WHEN ACTION = 'START' AND NX_ACTION IS NULL THEN DATEDIFF(minute,Badge_IN_OUT_TIME, GETDATE())
         END) TotalMinutesSpent
FROM(
    select *,
    LEAD(Badge_IN_OUT_TIME,1) OVER(Partition by UserName,Task_Code  ORDER BY  Badge_IN_OUT_TIME) NX_TIME,
    LEAD(ACTION,1) OVER(Partition by UserName,Task_Code ORDER BY  Badge_IN_OUT_TIME) NX_ACTION
    from #tmp
    ) X
CROSS APPLY(SELECT UserName,
                MAX(CASE WHEN Action = 'START' THEN Badge_IN_OUT_TIME END) ST_TIME,
                MAX(CASE WHEN Action = 'END' THEN Badge_IN_OUT_TIME END) ED_TIME 
                FROM #tmp t1 
                    WHERE t1.UserName = X.UserName 
                            and t1.Task_Code = X.Task_Code 
                GROUP BY UserName, Task_Code
            ) Y
GROUP BY X.USERNAME,X.Task_Code ,Y.ST_TIME,Y.ED_TIME