按时间顺序计算连续的列值并在另一个表中更新结果

问题描述 投票:0回答:1

桌子

Customer

ID 动作 日期 时间
10 优惠 26.04.2023 15:00
10 见面 25.04.2023 14:15
10 电话 24.04.2023 13:00
10 等等 23.04.2023 12:00
201 等等 15.04.2023 14:30
201 等等 15.04.2023 13:30
201 电话 15.04.2023 12:30
201 电话 15.04.2023 11:30
201 等等 15.04.2023 10:30
3020 等等 6.10.2021 8:00
3020 等等 5.10.2021 8:00
3020 电话 2021 年 10 月 4 日 8:00
3020 等等 2.10.2021 8:00
3020 等等 1.10.2021 8:00
3020 等等 1.10.2021 8:00

我需要找出每个 ID 的等待记录。

连续等待的定义是:

  1. ID
    的最新行开始,如果
    Action
    Wait
    则wait-streak = 1
  2. 如果具有相同
    ID
    的下一个时间顺序的行有
    Action
    =
    Wait
    ,等待连胜增加1
  3. ID
    的所有行按时间顺序循环,如果连胜继续,则等待连胜加 1
  4. 如果
    Wait
    有多个条纹,必须找到最大的并且必须保留最新条纹的值

除了

Date
,还必须考虑
Time
。将这些组合到一个新的日期/时间列中更好,还是有一种使用现有列的简单方法?

在计算之后或期间,结果应更新到新表中。

BiggestWaitStreak
列中发现的最长连胜,
NewestWaitStreak
列中的最新连胜,如果最新的
Action
Wait
,则
NewestIsWait
列必须设置为 1.

更新后新的统计表应该是这样的:

桌子

ContactStats

ID BiggestWaitStreak NewestWaitStreak NewestIsWait
10 1 1 0
201 2 2 1
3020 3 2 1

我想实现这一目标的最佳方法是利用 CTE 或临时表。我个人更喜欢 CTE。我很乐意添加我正在进行的工作,但不幸的是没有。我不知道从哪里开始。

非常感谢任何帮助。

sql sql-server tsql common-table-expression gaps-and-islands
1个回答
1
投票

这是一个经典的缺口和孤岛问题

查找数据孤岛的经典解决方案是使用

LAG
和/或
LEAD
找到孤岛的开始/结束,然后使用窗口化的
COUNT
为每个部分创建一个 ID。

然后只需使用更多基于该 ID 分配的窗口函数即可。有一个轻微的调整,

NewestIsWait
可以使用
FIRST_VALUE
单独计算。

WITH PrevValues AS (
    SELECT *,
      PrevAction = LAG(Action) OVER (PARTITION BY ID ORDER BY Date DESC, Time DESC),
      NewestIsWait = CASE WHEN
          FIRST_VALUE(Action) OVER (PARTITION BY ID ORDER BY Date DESC, Time DESC ROWS UNBOUNDED PRECEDING)
          = 'Wait' THEN 1 ELSE 0 END
    FROM YourTable
),
Grouped AS (
    SELECT *,
      GroupId = COUNT(CASE WHEN Action = 'Wait' AND (PrevAction <> 'Wait' OR PrevAction IS NULL) THEN 1 END)
        OVER (PARTITION BY ID ORDER BY Date DESC, Time DESC ROWS UNBOUNDED PRECEDING)
    FROM PrevValues
),
Counted AS (
    SELECT *,
      StreakLength = COUNT(CASE WHEN Action = 'Wait' THEN 1 END)
        OVER (PARTITION BY ID, GroupId)
    FROM Grouped
)
SELECT
  ID,
  Action,
  Date,
  Time,
  BiggestWaitStreak = MAX(StreakLength) OVER (PARTITION BY ID),
  NewestWaitStreak = MIN(CASE WHEN GroupId = 1 THEN StreakLength END) OVER (PARTITION BY ID),
  NewestIsWait
FROM Counted;

db<>小提琴

我建议你考虑将

Date
Time
列合并为一个。

© www.soinside.com 2019 - 2024. All rights reserved.