如何解决查找多个滑入/滑出时间戳之间的总分钟数 - 从垂直行中选择多个记录并转换水平行
我正在处理 sql Server 查询,以获取将处理多个任务代码的用户列表的 Badge Out Time - Bade In Time。
task_mgmt - 表名
表格列如下
Task_Sn | 用户名 | Task_Code | 动作 | Badge_IN_OUT_TIME |
---|---|---|---|---|
1 | 安迪 | 博客 | 开始 | 2021-07-20 08:11:45.000 |
2 | 安迪 | 博客 | END | 2021-07-20 10:11:45.000 |
3 | 贝基 | ACCTS | 开始 | 2021-07-20 11:11:45.000 |
4 | 贝基 | ACCTS | END | 2021-07-20 12:11:45.000 |
5 | 安迪 | 博客 | 开始 | 2021-07-20 12:15:45.000 |
6 | 安迪 | 博客 | END | 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 | END | 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 Mins(5 分钟) )
解决方法
在您的示例数据中,安迪的最后开始时间早于他的最后结束时间,因此造成了重叠。鉴于您如何描述计算总分钟数的逻辑,我假设这是不正确的。因此,在我的示例表中,我进行了相应的调整。
考虑以下事项:
我使用带有 LEAD() 函数的派生表来捕获下一个日期和操作的位置。我在我的外部查询中使用它来根据我的下一步行动来确定使用的分钟数。
我使用交叉申请来确定用户名和任务的最大开始和结束日期。
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,'END','2021-07-20 10:11:45.000'),(3,'Becky','ACCTS','2021-07-20 11:11:45.000'),(4,'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:35:00.000'),(8,'2021-07-20 13:00:00.000'),(9,'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,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,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,Y.ST_TIME,Y.ED_TIME
,
这似乎有效:
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
,但整数是更好一点,可能更高效)。
还要注意 ISNULL
中的 DATEDIFF
,当日期为 GETDATE
时,它会替换 NULL
。
如果需要对多个区间求和,可以使用GROUP BY
。
我提供了答案,但我知道预期结果中缺少两列。
注意:这两列 Badge_IN_TIME Badge_OUT_TIME 缺失,因为我不确定您要为这两列检索什么,如果您能澄清结果并这些两列的预期值如您为 TOTAL_TIME_SPENT 显示的方式我可以编辑问题并添加这两列推导。
将逻辑添加到上述列后 这是我的查询返回的内容。我认为预期的答案也有一些问题,因为它应该符合逻辑。
SELECT
DISTINCT
UserName,( 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,[Action] order by UserName ) as Total_MinsSpend
FROM
(
SELECT
Task_sn,UserName,[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,iSNULL( LEAD(Badge_IN_OUT_Time) over (Partition 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')
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。