如果您有 SQL Server 2014,则可以使用 LAG 或 LEAD 函数来查看其他行,这很容易:
Select PersonId, Sum(InfrequentPayment) InfrequentPayments
from
(
select PersonId
, case
when dateadd(day,@period,paymentdate) < coalesce(lead(PaymentDate) over (partition by personid order by PaymentDate),getutcdate())
then 1
else 0
end InfrequentPayment
from @Payment
) x
Group by PersonId
演示:http://sqlfiddle.com/#!6/9eecb7d/491
说明:
外部 SQL 相当简单;我们获取内部 SQL 的结果,按 PersonId 分组,并计算/总结他们支付的次数,判断为不频繁。
内部SQL也很简单;我们正在选择每条记录,记下该人以及该笔付款(或更确切地说是付款后的延迟)是否被判定为不频繁。
案例陈述决定了不经常付款的构成。
这里我们说,如果记录的 paymentdate 加上 90 天仍然早于下一次付款(如果是最后一次付款,则为当前日期,因此没有下一次付款),那么它是罕见的 (1);否则不是 (0)。
coalesce 只是用来处理一个人的最后一条记录;即,如果没有下一次付款,则使用当前日期(从而捕获上次付款时间超过今天 90 天的任何人)。
现在是“聪明”位:lead(PaymentDate) over (partition by personid order by PaymentDate)。
LEAD 是一个新的 SQL 函数,可以让您查看当前记录之后的记录(LAG 是查看上一条记录)。
如果您熟悉row_number() 或rank(),您可能已经了解这里发生了什么。
但是,要确定当前记录之后的记录,我们不查看当前查询;相反,我们只为这个函数指定一个order by 子句;这就是over 关键字后面括号中的内容。
我们还只想将每个人的付款日期与他们进行的其他付款进行比较;不是任何客户。为此,我们使用partition by 子句。
我希望这有意义/符合您的要求。如果有什么不清楚的地方请说出来,我会尽力改进我的解释。
编辑
对于老版本的SQL,使用或ROW_NUMBER和LEFT OUTER JOIN可以达到同样的效果;即
;with cte (PersonId, PaymentDate, SequenceNo) as
(
select PersonId
, PaymentDate
, ROW_NUMBER() over (partition by PersonId order by PaymentDate)
from @Payment
)
select a.PersonId
, sum(case when dateadd(day,@period,a.paymentdate) < coalesce(b.paymentdate,getutcdate()) then 1 else 0 end) InfrequentPayments
from cte a
left outer join cte b
on b.PersonId = a.PersonId
and b.SequenceNo = a.SequenceNo + 1
Group by a.PersonId
应该适用于大多数数据库的另一种方法(虽然效率较低)
select PersonId
, sum(InfrequentPayment) InfrequentPayments
from
(
select PersonId
, case when dateadd(day,@period,paymentdate) < coalesce((
select min(PaymentDate)
from @Payment b
where b.personid = a.personid
and b.paymentdate > a.paymentdate
),getutcdate()) then 1 else 0 end InfrequentPayment
from @Payment a
) x
Group by PersonId