【问题标题】:Calculate Number of Consecutive Days Where a Condition Applies Across Two Columns计算条件适用于两列的连续天数
【发布时间】:2020-10-19 22:39:51
【问题描述】:

我有一个类似于下面的表格:

+-------------------------+
¦ ID ¦ Date     ¦ Balance ¦
¦----+----------+---------¦
¦ A  ¦ 20200620 ¦ 150     ¦
¦ A  ¦ 20200621 ¦ -130    ¦
¦ A  ¦ 20200621 ¦ -140    ¦
¦ A  ¦ 20200621 ¦ -200    ¦
¦ A  ¦ 20200622 ¦ 200     ¦
¦ A  ¦ 20200622 ¦ 300     ¦
¦ B  ¦ 20200621 ¦ 350     ¦
¦ B  ¦ 20200621 ¦ 400     ¦
¦ B  ¦ 20200621 ¦ -150    ¦
¦ B  ¦ 20200622 ¦ -200    ¦
¦ B  ¦ 20200622 ¦ -300    ¦
¦ B  ¦ 20200623 ¦ -400    ¦
¦ B  ¦ 20200623 ¦ -500    ¦
+-------------------------+

我需要计算到达 ID 和每个不同日期(包括计算中的日期本身)的“余额

+--------------------------------------------+
¦ ID ¦ Date     ¦ Number_of_Consecutive_Days ¦
¦----+----------+----------------------------¦
¦ A  ¦ 20200620 ¦ Null                       ¦
¦----+----------+----------------------------¦
¦ A  ¦ 20200621 ¦ 1                          ¦
¦----+----------+----------------------------¦
¦ A  ¦ 20200622 ¦ 1                          ¦
¦----+----------+----------------------------¦
¦ B  ¦ 20200621 ¦ Null                       ¦
¦----+----------+----------------------------¦
¦ B  ¦ 20200622 ¦ 2                          ¦
¦----+----------+----------------------------¦
¦ B  ¦ 20200623 ¦ 3                          ¦
+--------------------------------------------+

您能建议我一种计算方法吗?非常感谢。

【问题讨论】:

  • 我不明白第三行的值。如果负数日之间有正数日会怎样?
  • 用零代替空值不是更有意义吗?
  • 嗨@GordonLinoff,感谢您的回复。如果在同一天我们有负余额,则查询应计入当天。只要我们在给定日期至少有一个负余额,我们就会计算它。
  • 嗨@shawnt00,对我来说,将 Null 设为零更有意义,因为零意味着没有提供该标准的日期,但您认为使用零而不是 null 更容易吗?
  • 是的,我想我会主张零。它仍然会告诉您有多少日期符合条件。

标签: sql sql-server


【解决方案1】:

这是一种与过滤有关的间隙和孤岛问题。这是一种方法:

select t.*,
       row_number() over (partition by id, dateadd(day, - seqnum, date)
                          order by date
                         ) as Number_of_Consecutive_Days
from (select t.id, date, min(balance) as min_balance,
             row_number() over (partition by id order by date) as seqnum
      from t
      group by t.id, date
      having min(balance) < 0
     ) t;

这仅适用于负余额的日子。然后从日期中减去一个序号。对于相邻的日子,这是恒定的 - 因此外部 row_number() 的差异。

编辑:

如果您只想计算到给定日期为止任何负余额的天数,您可以使用:

select t.*,
       sum(case when min_balance < 0 then 1 else 0 end) over (partition by id order by date) as Number_of_Consecutive_Days
from (select t.id, date, min(balance) as min_balance
      from t
      group by t.id, date
     ) t;

【讨论】:

  • 感谢您的回复。我认为 EDIT: 更符合我的逻辑。但是,由于某些原因,它似乎不适用于我的数据。我认为它会计算某个日期之前所有负余额的天数,但我只需要具有此类标准的连续天数,而不是所有天数。有没有其他方法可以尝试? @戈登林诺夫
  • @Aliz 。 . .第一个计算连续天数。第二个计算总天数。您可以设置一个 dbfiddle 来验证这一点。
【解决方案2】:

请注意,日期之间的任何间隔都将被视为连续天数。

with data as (
    select id, date,
        case when min(balance) >= 0 then 0 else 1 end as tally,
        sum(case when min(balance) >= 0 then 1 else 0 end)
            over (partition by id order by date) as grp
    from t
    group by id, date
)
select id, date,
    sum(tally) over (partition by id, grp, tally order by date) as running_days
from data
order by id, date;

将缺少的日期视为非连续尝试:

    sum(case when min(balance) >= 0 then 1 else 0 end)
        over (partition by id order by date) +
    datediff(day, min(date) over (partition by id), date) -
    row_number() over (partition by id order by date) + 1 as grp

https://rextester.com/NKBZG48737

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多