【问题标题】:Get time periods between timestamp records when some duplicates exist当存在一些重复时,获取时间戳记录之间的时间段
【发布时间】:2021-06-13 13:59:20
【问题描述】:

这是我的示例数据:

declare @Test table (SiteIdentifier int, SysTm datetime2(0), Signalet varchar(21));

insert into @Test (SiteIdentifier, SysTm, Signalet)
values
(587451, '2021-02-28 20:12:03', 'Joined'),
(587451, '2021-03-01 00:00:00', 'Left'),
(587451, '2021-03-04 07:12:17', 'Joined'),
(587451, '2021-03-05 02:13:03', 'Left'),
(587451, '2021-03-05 02:13:03', 'Left'),
(587451, '2021-03-05 07:13:00', 'Joined'),
(587451, '2021-03-08 01:04:07', 'Joined');

这是一个几乎解决了我的问题的查询:

with cte as (
    select *
      , row_number() over (partition by SiteIdentifier, Signalet order by SysTm) rn
    from @Test
)
select C1.SiteIdentifier, C1.SysTm, coalesce(C2.SysTm, C3.SysTm), datediff(hour, C1.SysTm, coalesce(C2.SysTm, C3.SysTm))
from cte C1
left join cte C2 on C2.SiteIdentifier = C1.SiteIdentifier and C2.Signalet = 'Joined' and C2.rn = C1.rn and C2.SysTm > C1.SysTm
left join cte C3 on C3.SiteIdentifier = C1.SiteIdentifier and C3.Signalet = 'Joined' and C3.rn = C1.rn + 1 and C3.SysTm > C1.SysTm and C2.rn is null
where C1.Signalet = 'Left'
order by C1.SysTm asc;

只要SignaletLeftJoinedLeftJoinedSiteIdentifier 之间交替,它就可以工作。

但是,在实时数据中,有时Joined(或Left)可能在几毫秒内出现两次 - 如示例数据所示。因此,当JoinedLeft 连续多次出现时,应忽略除第一条记录之外的所有记录。如果是Joined,第一条记录也应该如此,因为序列必须始终以Left 开头。

然后我需要计算Left 和下面的Joined 记录之间的时间差。

    (587451, '2021-02-28 20:12:03', 'Joined'),<-- Skipped
    (587451, '2021-03-01 00:00:00', 'Left'),<-- Used
    (587451, '2021-03-04 07:12:17', 'Joined'),<-- Used
    (587451, '2021-03-05 02:13:03', 'Left'),<-- Skipped
    (587451, '2021-03-05 02:13:03', 'Left'),<-- Used
    (587451, '2021-03-05 07:13:00', 'Joined'),<-- Skipped
    (587451, '2021-03-08 01:04:07', 'Joined');<-- Used

以上示例数据的结果应如下所示:

    ID     Left                  Joined                Hours
    587451 '2021-03-01 00:00:00' '2021-03-04 07:12:17' 79
    587451 '2021-03-05 02:13:03' '2021-03-05 07:13:00' 5

忽略第一个Joined(上面的查询确实如此),因为它前面没有Left。但是,我的查询无法产生这个结果,因为时间有两个相等的Signalet 一个接一个,而不是交替出现。

更新数据/问题:
这是来自 live 表的 actual 数据,它返回 NULL:

    ID
    15220 '2021-03-13 23:19:57.243' Left
    15220 '2021-03-15 05:54:01.027' Joined
    15220 '2021-03-15 23:29:44.043' Left
    15220 '2021-03-16 05:30:27.790' Joined

使用上面更新的查询返回:

    15220 '2021-03-13 23:19:57.243' NULL NULL
    15220 '2021-03-15 23:29:44.043' NULL NULL

它注册了正确的行,但它无法“找到”joinedHours

说明:
我试图在hours 中获得difference,在Left 信号和Joined 信号之间(所有信号都在同一个表中,因此是CTE)。需要考虑的是,第一个信号可以是Joined,也可以是两个Left,也可以是两个Joined一个接一个的信号。如果第一个信号是Joined,则忽略它并移动到Left的第一个出现处,当有两个Joined或两个Left紧接在另一个之后,只使用两者中的第一个,忽略最后一个。

【问题讨论】:

  • 我不明白这里的问题,你似乎并没有真正问一个。一个问题本身就应该是完整的,看来您之前的问题需要在这里阅读,以便我们尝试回答这个问题。 Edit这个问题给我们这个问题的所有细节。
  • 如果您能解释一下您要完成的工作,那将非常有帮助。它似乎埋在某个地方,但真的很难弄清楚你在做什么。
  • 我编辑了问题并添加了一个解释部分,试图逐步解释我想要完成的工作。

标签: sql sql-server tsql common-table-expression


【解决方案1】:

以下给出了预期的结果。它通过消除在第一个 CTE 中重复的行来完成。然后使用您现有的 CTE 作为第二个。因此,它为每个 SiteIdentifier 提供lags Signalet,然后删除任何重复的。

如果第一行是“已加入”,我什至设法过滤掉它,从而消除了对原始第二个加入的需要。

with cte1 as (
    select *
        , lag(Signalet) over (partition by SiteIdentifier order by SysTm asc) SignaletLagged
        , row_number() over (partition by SiteIdentifier order by SysTm) rn1
    from @Test
),
cte2 as (
    select *
        , row_number() over (partition by SiteIdentifier, Signalet order by SysTm) rn2
    from cte1
    -- Ignore repeated rows i.e. only take the first
    where (SignaletLagged is null or Signalet != SignaletLagged)
    -- Ignore groups which start with Joined, we need a left to start.
    and not (rn1 = 1 and Signalet = 'Joined')
)
select C1.SiteIdentifier, C1.SysTm [Left], C2.SysTm [Joined], datediff(hour, C1.SysTm, C2.SysTm) [Hours]
from cte2 C1
left join cte2 C2 on C2.SiteIdentifier = C1.SiteIdentifier and C2.Signalet = 'Joined' and C2.rn2 = C1.rn2 and C2.SysTm > C1.SysTm
where C1.Signalet = 'Left'
order by C1.SysTm asc;

返回:

SiteIdentifier Left Joined Hours
587451 2021-03-01 00:00:00 2021-03-04 07:12:17 79
587451 2021-03-05 02:13:03 2021-03-05 07:13:00 5

【讨论】:

  • 现在测试 :) 我会尽快回复您
  • @Geir note 我刚刚通过删除第二个连接对其进行了改进。
  • @[Dale K] 我测试了查询,但它返回 NULL,我不明白为什么。我使用了您的最新编辑,并使用来自实时数据库的新 ACTUAL 数据编辑了问题。
  • @Geir 在这个阶段我建议你花时间学习/理解查询是如何工作的,然后调试它。如果我站在你的立场上,让陌生人给我写一个相当复杂的查询,而我无法维护,我会对此感到不舒服。上面的查询有 3 个部分,从第一个开始,看到它返回正确的数据,添加第二个,然后再次查看返回的数据,然后添加第三个。在某些时候,您会看到不应该并且能够解决问题的数据被排除/包含。
  • 如果不了解(至少是基础知识)查询的作用,我从来不会在数据库中实现某些东西。我从来没有使用过 LAG 功能,所以我正在阅读那个功能。我只需要继续调试一切并尽力而为......
猜你喜欢
  • 2016-01-19
  • 2015-06-18
  • 2018-05-29
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
相关资源
最近更新 更多