查找列包含值的连续天数

8gsdolmq  于 2022-10-22  发布在  其他
关注(0)|答案(2)|浏览(138)

让我们想象一下,我们有一个员工列表,每天我们都在其中跟踪他们的任务列表。如果该列表包含我们称为“关键”的内容,我们可以指定一个布尔值,在这种情况下,让我们假设被要求锁门的人有“关键”任务。
对于这一额外的责任,我们希望奖励那些证明自己有能力连续完成给定天数任务的员工。
我有一份关键任务清单,每天都能成功地标记这些任务,但我很难弄清楚如何正确应用计数器。
理想情况下,当我们在他们的task_list中找到一个关键任务时,它会连续增加一天,当他们没有关键任务时会重置为0。
下面是所需输出的示例:
|员工|天|任务列表|关键任务| Consec_Days_Crity_Task|
| ------------ | ------------ | ------------ | ------------ | ------------ |
|Tom J | 10/1/22 |清扫、锁门*|1|1|
|Tom J | 10/2/22 |清扫,锁门*|1|2|
|Tom J |10/3/22 |拖把,盘子|0|0|
|Tom J | 10/4/22 |清扫、锁门*|1|1|
|苏B |10/1/22|拖把,盘子|0|0|
|苏B |10/2/22 |拖把,盘子|0|0|
|苏B |10/3/22 |清扫,锁门*|1|1|
|苏B |10/4/22 |拖把,盘子|0|0|
我能够将前4列放入临时表中。没问题,我尝试过使用循环来更新这些计数器值,也尝试过使用滞后函数之类的东西。我想,我似乎无法理解如何编写分区语句。
有什么建议吗?

gdx19jrr

gdx19jrr1#

这是一个间隙和孤岛问题,对于每个员工,您需要确定Critical_Task=1(孤岛)所在的连续行组和Critical_Task=0的连续行(间隙)所在的组。之后,您可以使用count窗口函数对定义的组中每个员工的Critical_Task=1处的连续行进行计数。

SELECT Employee, Day, Task_List, Critical_Task, 
       COUNT(CASE WHEN Critical_Task=1 THEN Task_List END) OVER 
       (PARTITION BY Employee, grp ORDER BY Day) Consec_Days_Crit_Task
FROM
(
  SELECT *,
     ROW_NUMBER() OVER (PARTITION BY Employee ORDER BY Day) -
     ROW_NUMBER() OVER (PARTITION BY Employee,Critical_Task ORDER BY Day) AS grp
  FROM Table_Name
) T
ORDER BY Employee DESC, Day

ROW_NUMBER() OVER ... AS grp用于识别所需的组。
请参阅demo

nimxete2

nimxete22#

我们可以在同一数据上留下连接,以确定非关键任务限制当前记录的最长日期。然后,只需使用DATEDIFF()函数计算自上一个0开始的连续天数。
我已经使用了前四列的示例数据,并将它们插入到表变量中,以便在下面的示例中使用:

DECLARE @Data as TABLE (
  Employee varchar(50), 
  Day date, 
  Task_List varchar(50), 
  Critical_Task bit)

INSERT INTO @Data
VALUES ('Tom J', '10/1/22', 'Sweep, Lock Door*', 1)
  ,('Tom J', '10/2/22', 'Sweep, Lock Door*', 1)
  ,('Tom J', '10/3/22', 'Mop, Dishes', 0)
  ,('Tom J', '10/4/22', 'Sweep, Lock Door*', 1)
  ,('Sue B', '10/1/22', 'Mop, Dishes', 0)
  ,('Sue B', '10/2/22', 'Mop, Dishes', 0)
  ,('Sue B', '10/3/22', 'Sweep, Lock Door*', 1)
  ,('Sue B', '10/4/22', 'Mop, Dishes', 0);

SELECT Employee, Day, Task_List, Critical_Task
  , DATEDIFF(day, last_0, Day) as Consec_Days_Crit_Task
FROM (
    SELECT a.*
        , coalesce(max(b.Day), 
            dateadd(day, -1, min(a.Day) over(partition by a.employee))) as last_0
    FROM @Data as a
    LEFT JOIN @Data as b
        ON a.Employee = b.Employee AND b.Critical_Task = 0 AND a.Day >= b.Day
    GROUP BY a.Employee, a.Day, a.Task_List, a.Critical_Task
) as a;

相关问题