SQL 差距和孤岛问题与扭曲 - 根据前一个标志的持续时间重置标志

Posted

技术标签:

【中文标题】SQL 差距和孤岛问题与扭曲 - 根据前一个标志的持续时间重置标志【英文标题】:SQL Gaps and Island problem with a twist -- reset a flag based on duration from previous flag 【发布时间】:2019-08-01 19:52:36 【问题描述】:

我有一个电话数据集,其中包含客户的通话日期和通话结果(状态)。如果最近一次付费电话已经 >= 5 天,我想为每个售出电话向我的销售代表付款。

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

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

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)

;

我想在我的表中添加 PaidCall 标志,如下表所示。 Days_Since_Paid_Call 只是为了说明我是如何提出付费电话专栏的。

【问题讨论】:

在 DDL 中你有 Status 但图片上的 Quote 是什么? @nikeshpraj 。 . .这会很昂贵,因为您需要使用递归 CTE。 【参考方案1】:

不幸的是,您需要迭代处理数据。一种方法是使用递归 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 是一个 dbfiddle。

【讨论】:

以上是关于SQL 差距和孤岛问题与扭曲 - 根据前一个标志的持续时间重置标志的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:寻找就业差距——孤岛和差距问题

SQL Server - 计算会话数 - 差距和孤岛

使用差距和孤岛知识找到最长时间不改变就业(SQL)

分组依据基于 Redshift 中的后续标志(间隙和孤岛问题)

差距和孤岛问题 - 查询不适用于所有时期

差距和孤岛 - Microsoft Access