查找多次滑动之间的总分钟数 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
我正在处理 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