查找不同时间间隔的票号的循环时间

Posted

技术标签:

【中文标题】查找不同时间间隔的票号的循环时间【英文标题】:Find the cycle time of a ticket number for different intervals 【发布时间】:2020-02-14 16:17:36 【问题描述】:
TicketNo    ActionDate                  OldStatus    NewStatus      CycleTime/Sec  
1001        2014-02-14 10:17:05.000     Assigned     InProgress     -
1001        2014-03-05 02:03:44.000     InProgress   Reply          1611999
1001        2014-03-11 10:00:14.000     Reply        Resolved       546990
1002        2015-03-20 04:44:14.000     InProgress   Reply          -
1002        2015-03-21 05:40:02.000     Reply        Resolved       89748

我必须为工单状态的每次变化计算周期时间。

在上面的示例中,我正在尝试计算工单从旧状态路由到新状态时从操作日期算起的秒数。

我尝试使用排名功能,但没有得到想要的输出。

选择 * ,row_number() over (partition by a.ticketno, a.oldstatus order by a.actiondate) rn

来自票务

如果有人能提出一些解决此计算的想法,我将不胜感激。

【问题讨论】:

请添加您最好尝试的问题。 【参考方案1】:

我采用了 Sean 的出色解决方案并对其进行了调整以避免排序。我正在使用一个临时表,以便我可以从我即将发布的执行计划中排除临时变量的创建/填充。

-- Temp table with sample data
IF OBJECT_ID('tempdb..#Something') IS NOT NULL DROP TABLE #Something;
CREATE TABLE #Something
(    TicketNo INT
    , ActionDate DATETIME
    , OldStatus  VARCHAR(50)
    , NewStatus  VARCHAR(50)
);
INSERT #Something VALUES
  (1001, '2014-02-14 10:17:05.000', 'Assigned', 'InProgress')
, (1001, '2014-03-05 02:03:44.000', 'InProgress', 'Reply')
, (1001, '2014-03-11 10:00:14.000', 'Reply', 'Resolved')
, (1002, '2015-03-20 04:44:14.000', 'InProgress', 'Reply')
, (1002, '2015-03-21 05:40:02.000', 'Reply', 'Resolved')

-- TOP (1) Solution
SELECT s.TicketNo, s.ActionDate, s.OldStatus, s.NewStatus,
       CycleTimeSeconds = DATEDIFF(SECOND, MyLag.ActionDate, s.ActionDate)
FROM   #Something AS s
OUTER APPLY
(
    SELECT TOP (1) ActionDate
    FROM     #Something s2 
    WHERE    s2.TicketNo   = s.TicketNo 
    AND      s2.ActionDate < s.ActionDate
    ORDER BY s2.ActionDate DESC
) AS MyLag;

-- Using MAX instead of TOP (1) to avoid a DESC sort operation
SELECT s.TicketNo, s.ActionDate, s.OldStatus, s.NewStatus,
       CycleTimeSeconds = DATEDIFF(SECOND, MyLag.ActionDate, s.ActionDate)
FROM #Something AS s
CROSS APPLY
(
    SELECT ActionDate = MAX(ActionDate)
    FROM   #Something s2 
    WHERE  s2.TicketNo   = s.TicketNo 
    AND    s2.ActionDate < s.ActionDate 
) AS MyLag;

由于子查询只评估一列,我们可以利用没有GROUP BY 的聚合函数。因为我使用的是聚合 (MAX),所以我总是会返回一行,这就是我将 OUTER APPLY 更改为 CROSS APPLY 的原因。 OUTER APPLY 没有任何问题,但更改它会从该执行计划中删除标量运算符 - 没有性能提升,只是一个更清晰的执行计划。

这种方法还有一个非常大的额外好处:它不仅避免了排序,而且还避免了 DESCending 排序。如果ActionDate 上有索引,则优化器可以利用它通过执行 *ordered-backward 扫描来避免 DESCending 排序。将 ActionDate 上的唯一约束添加到原始临时变量(我不建议这样做,但它适用于本示例)运行由 ActionDate DESC 排序的TOP (1) 查询。

declare @Something table
(
    TicketNo int
    , ActionDate datetime UNIQUE
    , OldStatus varchar(50)
    , NewStatus varchar(50)
)

insert @Something values
  (1001, '2014-02-14 10:17:05.000', 'Assigned', 'InProgress')
, (1001, '2014-03-05 02:03:44.000', 'InProgress', 'Reply')
, (1001, '2014-03-11 10:00:14.000', 'Reply', 'Resolved')
, (1002, '2015-03-20 04:44:14.000', 'InProgress', 'Reply')
, (1002, '2015-03-21 05:40:02.000', 'Reply', 'Resolved')

SELECT TOP (1) ActionDate
FROM     @Something AS s2 
ORDER BY s2.ActionDate DESC;

注意向后扫描:

向后扫描会杀死并行性。 Itzik Ben-Gan 在这里讨论:Avoiding a Sort with Descending Order。

有序前向扫描和有序后向扫描之间的一个区别是 前者可以潜在地使用并行性,而后者 目前在 存储引擎

这里的 APPLY 允许我们在需要时在优化器的后袋中进行无排序操作并行处理。只是更多的证据表明 APPLY 很棒...不需要任何进一步的证据;)

【讨论】:

艾伦一如既往地干得好。如果我在其中加入任何循环,我会得出相同(或相似)的解决方案。很确定 LAG 无论如何都会让它过时。因此,如果 OP 使用受支持的版本,我们将不会进行此讨论。 :)【参考方案2】:

最简单的方法是使用 LAG。您可以在此处阅读有关 LAG 功能的更多信息。 https://docs.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql?view=sql-server-ver15

这是一个功能齐全的示例。

declare @Something table
(
    TicketNo int
    , ActionDate datetime
    , OldStatus varchar(50)
    , NewStatus varchar(50)
)

insert @Something values
(1001, '2014-02-14 10:17:05.000', 'Assigned', 'InProgress')
, (1001, '2014-03-05 02:03:44.000', 'InProgress', 'Reply')
, (1001, '2014-03-11 10:00:14.000', 'Reply', 'Resolved')
, (1002, '2015-03-20 04:44:14.000', 'InProgress', 'Reply')
, (1002, '2015-03-21 05:40:02.000', 'Reply', 'Resolved')

select s.*
    , CycleTimeSeconds = datediff(second, lag(ActionDate, 1) over(partition by TicketNo order by ActionDate), s.ActionDate)
from @Something s

--编辑--

这是一个适用于 Sql Server 2008 的版本(您确实应该考虑升级,因为不再支持该版本)。

select s.*
    , CycleTimeSeconds = datediff(second, MyLag.ActionDate, s.ActionDate)
from @Something s
outer apply 
(
    select top 1 ActionDate 
    from @Something s2 
    where s2.TicketNo = s.TicketNo 
        and s2.ActionDate < s.ActionDate 
    order by ActionDate desc
) MyLag

【讨论】:

。 .我不知道你回答的时候SQL Server 2008标签是否在问题上,但它不支持lag().. @GordonLinoff 哦,亲爱的...我没有注意到它被标记为 2008。我愚蠢地认为人们已经升级了,因为该版本不再受支持。 已更新为可在 sql server 2008 中使用的版本。 嘿@SeanLange - 我刚刚添加了你答案的调整版本 - 我想你会喜欢的。 谢谢大家的解决方案。

以上是关于查找不同时间间隔的票号的循环时间的主要内容,如果未能解决你的问题,请参考以下文章

如何查找两个不同日期字段SQL在一定时间间隔内是不是匹配?

auto js for循环怎么分别运行两个不同的时间间隔的两个不同坐标的点击循环?

Postgresql SQL在发票号上查找不同部门的收入

如何根据关键和时间间隔有效地查找父记录?

C# 要想给一个死循环设置循环时间间隔,每5秒循环一次。

android循环播放图片的时间间隔设置问题