如何判断一份合同是否跨行有效?

How to determine if a contract is valid across multiple lines?

我正在尝试写一些 SQL 来确定和分组合同是否在多个不同的行中有效。

场景如下,我有一个 table 存储有效期为 364 天的合同。有一行用于合同的初始启动,然后一行用于续订。当合同过期或关闭时,还有另一行关闭。有两种不重叠的合同。如果此人转到另一份合同,则旧合同将被关闭。合同没有唯一标识,但人有唯一 ID。

下面是我查看数据的结果。

SELECT CA.ConDate, CA.IsCon, DATEADD(MILLISECOND, 10 * CA.IsCon, CA.ConDate), CA.RenewalStatus, CA.PersonID
FROM dbo.ConActivity CA
WHERE CA.RenewalStatus IN ( 1, 2 )
      AND CA.PersonID = '254915C5-2F30-40C9-B7E9-0239E6CBE27B'
ORDER BY DATEADD(MILLISECOND, 10 * CA.IsCon, CA.ConDate)

这returns结果如下:

ConDate                 IsCon  (No column name)         RenewalStatus   PersonID
2018-01-12 00:00:00.000 0      2018-01-12 00:00:00.000  1               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2018-03-30 00:00:00.000 0      2018-03-30 00:00:00.000  2               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2018-06-26 00:00:00.000 0      2018-06-26 00:00:00.000  1               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2018-07-26 00:00:00.000 0      2018-07-26 00:00:00.000  1               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2019-07-02 00:00:00.000 0      2019-07-02 00:00:00.000  1               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2019-10-29 00:00:00.000 0      2019-10-29 00:00:00.000  2               254915C5-2F30-40C9-B7E9-0239E6CBE27B
2019-10-29 00:00:00.000 1      2019-10-29 00:00:00.010  1               254915C5-2F30-40C9-B7E9-0239E6CBE27B

续订状态:1 = 已续订(或已打开),2 = 已关闭

从数据中可以看出,合约可以先开后关一段时间(也就是一个时间段),然后在同一个合约类型下开仓续签几次,然后再转换成另一种合约类型合同(那是另一个时间段),然后在新合同类型中打开一个新合同并保持打开状态,直到关闭 RwnewalStatus (= 2)。 (无列名)只是我按正确顺序排列的行和我尝试用来确定时间范围的方法。

我想要每人每合同有效期一行,在这种情况下我想看到:

ConDate                 IsCon  ConEndDate               PersonID
2018-01-12 00:00:00.000 0      2018-03-30 00:00:00.000  254915C5-2F30-40C9-B7E9-0239E6CBE27B
2018-06-26 00:00:00.000 0      2019-10-29 00:00:00.000  254915C5-2F30-40C9-B7E9-0239E6CBE27B
2019-10-29 00:00:00.000 1      NULL                     254915C5-2F30-40C9-B7E9-0239E6CBE27B

你会如何实现这个结果?

假设您的 DBMS 支持 Windowed Aggregates:

with cte as 
 (
    SELECT CA.ConDate, CA.IsCon, 
       DATEADD(MILLISECOND, 10 * CA.IsCon, CA.ConDate) as col,
       CA.RenewalStatus, CA.PersonID,
       -- assign the same value to all rows of 1 followed by 2 using a Cumulative Sum
       sum(case when RenewalStatus = 2 then 1 else 0 end)
       over (partition by PersonID
             order by ConDate desc, RenewalStatus
             rows unbounded preceding) as grp
    FROM tab CA
    WHERE CA.RenewalStatus IN ( 1, 2 )
          AND CA.PersonID = '254915C5-2F30-40C9-B7E9-0239E6CBE27B'
 )
select min(ConDate), max(IsCon),
    case when max(RenewalStatus) = 2 then max(ConDate) end, PersonID
from cte
-- now aggregate over the person and the group's value
group by PersonId, grp