SQL 间隙和孤岛问题有一个转折——根据前一个标志的持续时间重置一个标志

SQL Gaps and Island problem with a twist -- reset a flag based on duration from previous flag

我有一个电话数据集,其中包含来自客户的通话日期和通话结果(状态)。如果最近一次付费通话时间 >= 5 天,我愿意为每次售出的通话支付我的销售代表费用。

下面是我的示例数据集,其中包含 table。另外,附上 table 的图片,其中包含我拥有的列和我想要的列。有色唱片是卖出电话;绿色记录是我想要的记录,红色记录是我不想支付的记录,即使它是已售出的电话。

我尝试了几个使用 window 函数的版本,但还没有成功。非常感谢任何帮助。

DECLARE @have TABLE
(
    CallDate DATE,
    Status VARCHAR(10)
);

INSERT INTO @have (CallDate, Status)
values
('2019-01-01', 'unsold'),
('2019-01-02', 'unsold'),
('2019-01-04', 'unsold'),
('2019-01-08', 'sold'),
('2019-01-09', 'sold'),
('2019-01-13', 'unsold'),
('2019-01-14', 'sold'),
('2019-01-19', 'unsold'),
('2019-01-21', 'unsold'),
('2019-01-22', 'sold'),
('2019-01-24', 'unsold'),
('2019-01-25', 'sold'),
('2019-01-29', 'sold'),
('2019-01-30', 'unsold'),
('2019-02-04', 'sold'),
('2019-02-05', 'sold'),
('2019-02-06', 'sold'),
('2019-02-11', 'sold'),
('2019-02-12', 'unsold'),
('2019-02-17', 'sold'),
('2019-02-18', 'unsold'),
('2019-02-19', 'unsold'),
('2019-02-20', 'sold')
;


DECLARE @want TABLE
(
    CallDate DATE,
    Status VARCHAR(10),
    PaidCall int, 
    Days_Since_Last_Paid_Call int
);

INSERT INTO @want (CallDate, Status, PaidCall, Days_Since_Last_Paid_Call)
values
('2019-01-01', 'unsold', 0, NULL),
('2019-01-02', 'unsold', 0, NULL),
('2019-01-04', 'unsold', 0, NULL),
('2019-01-08', 'sold', 1, NULL),
('2019-01-09', 'sold', 0, 1),
('2019-01-13', 'unsold', 0, NULL),
('2019-01-14', 'sold', 1, 6),
('2019-01-19', 'unsold', 0, NULL),
('2019-01-21', 'unsold', 0, NULL),
('2019-01-22', 'sold', 1, 8),
('2019-01-24', 'unsold', 0, NULL),
('2019-01-25', 'sold', 0, 3),
('2019-01-29', 'sold', 1, 7),
('2019-01-30', 'unsold', 0, NULL),
('2019-02-04', 'sold', 1, 6),
('2019-02-05', 'sold', 0, 1),
('2019-02-06', 'sold', 0, 2),
('2019-02-11', 'sold', 1, 7),
('2019-02-12', 'unsold', 0, NULL),
('2019-02-17', 'sold', 1, 6),
('2019-02-18', 'unsold', 0, NULL),
('2019-02-19', 'unsold', 0, NULL),
('2019-02-20', 'sold', 0, 3)

;

我想在我的 table 中添加 PaidCall 标志,如此 table 所示。 Days_Since_Paid_Call 仅用于说明目的,以解释我是如何提出“付费电话”列的。

不幸的是,您需要迭代处理数据。一种方法是使用递归 CTE:

with s as (
      select h.*, row_number() over (order by calldate) as seqnum
      from have h
      where status = 'sold'
     ),
     cte as (
      select calldate, seqnum, 1 as paidquote, calldate as paidquote_date
      from s
      where seqnum = 1
      union all
      select s.calldate, s.seqnum,
             (case when s.calldate > dateadd(day, 5, paidquote_date) then 1 else 0 end),
             (case when s.calldate > dateadd(day, 5, paidquote_date) then s.calldate else cte.paidquote_date end)
      from cte join
           s
           on s.seqnum = cte.seqnum + 1
     )
select h.calldate, h.status, coalesce(cte.paidquote, 0) as paidquote
from have h left join
     cte
     on h.calldate = cte.calldate
order by h.calldate;

Here 是一个 db<>fiddle.