给定多个开始时间时如何创建开始和停止时间?
How to create start & stop times when multiple start times are given?
我正在尝试量化活动时间与空闲时间,我需要做的第一件事是创建不同且离散的开始时间和结束时间。问题是数据库(有人告诉我这是一个错误)为事件创建了多个 "start" 次。更复杂的是,一个 "report" 可以有多个正在处理的实例,并且每个实例都应该记录为一个离散的持续时间。
例如,
WorkflowID ReportID User Action Timestamp
1 1 A Start 1:00
2 1 A Stop 1:03
3 1 B Start 1:05
4 1 B Start 1:06
5 1 B Stop 1:08
6 1 B Start 1:10
7 1 B Start 1:11
8 1 B Stop 1:14
我想编写一个 SQL 查询来输出以下内容:
User StartTime EndTime
A 1:00 1:03
B 1:05 1:08
B 1:10 1:14
我 运行 遇到的问题是 start/stop 事件的数量需要是任意的(每个用户每个 ReportID)。此外,需要删除系列中第一个 "start" 和随后的 "stop" 之间多余的 "start" 次,以免弄乱。
也许我遗漏了什么,但这对我来说很棘手。有什么想法吗?谢谢。
要删除重复数据,请使用 lag()
将用户之前的操作和报告与当前操作进行比较。如果它们相同,则为重复项,将其标记为重复项。然后使用 row_number()
对开始和停止进行编号,以便每对属于一起的开始和停止共享一个数字(每个报告和用户)。然后加入报告,用户和那个号码。
为方便起见,您可以使用 CTE 来构造查询并避免重复某些子查询的必要性。
WITH
[DeduplicatedAndNumbered]
AS
(
SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
row_number() OVER (PARTITION BY [ReportID],
[User],
[Action]
ORDER BY [Timestamp]) [Number]
FROM (SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
CASE
WHEN lag([Action]) OVER (PARTITION BY [ReportId],
[User]
ORDER BY [Timestamp]) = [Action] THEN
1
ELSE
0
END [IsDuplicate]
FROM [elbaT]) [x]
WHERE [IsDuplicate] = 0
),
[DeduplicatedAndNumberedStart]
AS
(SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
[Number]
FROM [DeduplicatedAndNumbered]
WHERE [Action] = 'Start'),
[DeduplicatedAndNumberedStop]
AS
(SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
[Number]
FROM [DeduplicatedAndNumbered]
WHERE [Action] = 'Stop')
SELECT [DeduplicatedAndNumberedStart].[User],
[DeduplicatedAndNumberedStart].[Timestamp] [StartTime],
[DeduplicatedAndNumberedStop].[Timestamp] [EndTime]
FROM [DeduplicatedAndNumberedStart]
INNER JOIN [DeduplicatedAndNumberedStop]
ON [DeduplicatedAndNumberedStart].[ReportId] = [DeduplicatedAndNumberedStop].[ReportId]
AND [DeduplicatedAndNumberedStart].[User] = [DeduplicatedAndNumberedStop].[User]
AND [DeduplicatedAndNumberedStart].[Number] = [DeduplicatedAndNumberedStop].[Number];
OP 用 sql-server-2008
标记了他们的问题。
由于 SQL Server 2008 缺少 lag()
功能(它是在 SQL Server 2012), here is a solution that uses Common Table Expressions and row_number() 中添加的,可从 SQL Server 2005 起使用...
;with [StopEvents] as (
select [WorkflowID],
[ReportID],
[User],
[EndTime] = [Timestamp],
[StopEventSeq] = row_number() over (
partition by [ReportID], [User], [Timestamp]
order by [Timestamp])
from Workflow
where [Action] = 'Stop'
)
select this.[User], [StartTime], this.[EndTime]
from [StopEvents] this
-- Left join here because first Stop event won't have a previous Stop event
left join [StopEvents] previous
on previous.[ReportID] = this.[ReportID]
and previous.[User] = this.[User]
and previous.[StopEventSeq] = this.[StopEventSeq] - 1
outer apply (
select [StartTime] = min([Timestamp])
from Workflow W
where W.[ReportID] = this.[ReportID]
and W.[User] = this.[User]
and W.[Timestamp] < this.[EndTime]
-- First Stop event won't have a previous, so just get the min([Timestamp])
and (previous.[EndTime] is null or W.[Timestamp] >= previous.[EndTime])
) thisStart
order by this.[User], this.[EndTime]
我正在尝试量化活动时间与空闲时间,我需要做的第一件事是创建不同且离散的开始时间和结束时间。问题是数据库(有人告诉我这是一个错误)为事件创建了多个 "start" 次。更复杂的是,一个 "report" 可以有多个正在处理的实例,并且每个实例都应该记录为一个离散的持续时间。
例如,
WorkflowID ReportID User Action Timestamp
1 1 A Start 1:00
2 1 A Stop 1:03
3 1 B Start 1:05
4 1 B Start 1:06
5 1 B Stop 1:08
6 1 B Start 1:10
7 1 B Start 1:11
8 1 B Stop 1:14
我想编写一个 SQL 查询来输出以下内容:
User StartTime EndTime
A 1:00 1:03
B 1:05 1:08
B 1:10 1:14
我 运行 遇到的问题是 start/stop 事件的数量需要是任意的(每个用户每个 ReportID)。此外,需要删除系列中第一个 "start" 和随后的 "stop" 之间多余的 "start" 次,以免弄乱。
也许我遗漏了什么,但这对我来说很棘手。有什么想法吗?谢谢。
要删除重复数据,请使用 lag()
将用户之前的操作和报告与当前操作进行比较。如果它们相同,则为重复项,将其标记为重复项。然后使用 row_number()
对开始和停止进行编号,以便每对属于一起的开始和停止共享一个数字(每个报告和用户)。然后加入报告,用户和那个号码。
为方便起见,您可以使用 CTE 来构造查询并避免重复某些子查询的必要性。
WITH
[DeduplicatedAndNumbered]
AS
(
SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
row_number() OVER (PARTITION BY [ReportID],
[User],
[Action]
ORDER BY [Timestamp]) [Number]
FROM (SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
CASE
WHEN lag([Action]) OVER (PARTITION BY [ReportId],
[User]
ORDER BY [Timestamp]) = [Action] THEN
1
ELSE
0
END [IsDuplicate]
FROM [elbaT]) [x]
WHERE [IsDuplicate] = 0
),
[DeduplicatedAndNumberedStart]
AS
(SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
[Number]
FROM [DeduplicatedAndNumbered]
WHERE [Action] = 'Start'),
[DeduplicatedAndNumberedStop]
AS
(SELECT [WorkflowID],
[ReportID],
[User],
[Action],
[Timestamp],
[Number]
FROM [DeduplicatedAndNumbered]
WHERE [Action] = 'Stop')
SELECT [DeduplicatedAndNumberedStart].[User],
[DeduplicatedAndNumberedStart].[Timestamp] [StartTime],
[DeduplicatedAndNumberedStop].[Timestamp] [EndTime]
FROM [DeduplicatedAndNumberedStart]
INNER JOIN [DeduplicatedAndNumberedStop]
ON [DeduplicatedAndNumberedStart].[ReportId] = [DeduplicatedAndNumberedStop].[ReportId]
AND [DeduplicatedAndNumberedStart].[User] = [DeduplicatedAndNumberedStop].[User]
AND [DeduplicatedAndNumberedStart].[Number] = [DeduplicatedAndNumberedStop].[Number];
OP 用 sql-server-2008
标记了他们的问题。
由于 SQL Server 2008 缺少 lag()
功能(它是在 SQL Server 2012), here is a solution that uses Common Table Expressions and row_number() 中添加的,可从 SQL Server 2005 起使用...
;with [StopEvents] as (
select [WorkflowID],
[ReportID],
[User],
[EndTime] = [Timestamp],
[StopEventSeq] = row_number() over (
partition by [ReportID], [User], [Timestamp]
order by [Timestamp])
from Workflow
where [Action] = 'Stop'
)
select this.[User], [StartTime], this.[EndTime]
from [StopEvents] this
-- Left join here because first Stop event won't have a previous Stop event
left join [StopEvents] previous
on previous.[ReportID] = this.[ReportID]
and previous.[User] = this.[User]
and previous.[StopEventSeq] = this.[StopEventSeq] - 1
outer apply (
select [StartTime] = min([Timestamp])
from Workflow W
where W.[ReportID] = this.[ReportID]
and W.[User] = this.[User]
and W.[Timestamp] < this.[EndTime]
-- First Stop event won't have a previous, so just get the min([Timestamp])
and (previous.[EndTime] is null or W.[Timestamp] >= previous.[EndTime])
) thisStart
order by this.[User], this.[EndTime]