-1
TableA (
    id int, 
    match1 char,
    match2 char,
    startdate datetime,
    enddate,
    status char
)

样本数据:

 id match1  match2   startdate   enddate        Status
 1  AAA     BBB      2006-01-01  2007-01-01 
 2  AAA     BBB      2006-12-12  2008-01-01
 3  AAA     BBB      2008-01-01  2012-02-02
 4  AAA     BBB      2002-01-01  2004-01-01
 5  DDD     EEE      2009-01-01  2012-01-01
 6  DDD     EEE      2011-01-01  2020-01-01
 7  DDD     EEE      2013-01-01  2015-01-01
 8  DDD     EFG      2009-01-01  2012-01-01

我必须在匹配时status填充,日期 - 开始和结束 - 相互重叠。'FAIL'tableAmatch1, match2

何时ID = 2,生效日期2006-12-122008-01-01,重叠ID = 1。所以,ID = 2得到'FAIL'. 也是如此ID = 6

预期结果:

 id match1  match2    startdate    enddate        Status
 1  AAA     BBB      2006-01-01  2007-01-01       NULL
 2  AAA     BBB      2006-12-12  2008-01-01       FAIL
 3  AAA     BBB      2008-01-01  2012-02-02       NULL
 4  AAA     BBB      2002-01-01  2004-01-01       NULL    
 5  DDD     EEE      2009-01-01  2012-01-01       NULL
 6  DDD     EEE      2011-01-01  2020-01-01       FAIL
 7  DDD     EEE      2013-01-01  2015-01-01       NULL
 8  DDD     EFG      2009-01-01  2012-01-01       NULL (because It has different match2)

此外,我们保留了相同 match1 和 match2 的第一条记录,并且使新传入的重叠记录失败。

4

2 回答 2

2

为什么 ID 7 不是失败的?它与 ID 6 重叠(相交)?

ID7 没有失败,因为 ID6 已经失败并从我们的考虑中排除

您在评论中提出的这一点消除了仅使用 SQL 解决方案的可能性,因为您的定义FAIL变得递归。换句话说,为了知道某事是否失败,仅知道日期startend日期是不够的:您还必须知道“上一代”记录的通过或失败状态。

这是一个可以帮助您确定第一个重叠 ID 的查询,忽略“与失败记录的重叠不计入”规则:

select a.*,(
    select top 1 b.id from tableA b
    where a.match1=b.match1 and a.match2=b.match2
    and a.startdate>b.startdate
    and (case when a.startdate<b.startdate then b.startdate else a.startdate end) <
    (case when a.enddate>b.enddate then b.enddate else a.enddate end)
    order by b.startdate asc
) as OverlappingId
from tableA a

它为您的表中的数据返回这些结果:

1   AAA BBB 2006-01-01  2007-01-01  NULL
2   AAA BBB 2006-12-12  2008-01-01  1
3   AAA BBB 2008-01-01  2012-02-02  NULL
4   AAA BBB 2002-01-01  2004-01-01  NULL
5   DDD EEE 2009-01-01  2012-01-01  NULL
6   DDD EEE 2011-01-01  2020-01-01  5
7   DDD EEE 2013-01-01  2015-01-01  6
8   DDD EFG 2009-01-01  2012-01-01  NULL

如果一定要注意“overlaps with failed”规则,需要依次应用;SQL 不是很擅长。

于 2011-12-28T22:29:51.513 回答
1

为此,您需要一个递归 CTE 或游标。下面的递归 CTE 方法。

;WITH BaseData(id,match1,match2,startdate,enddate)
     AS (SELECT 1,'AAA','BBB','2006-01-01','2007-01-01' UNION ALL
         SELECT 2,'AAA','BBB','2006-12-12','2008-01-01' UNION ALL
         SELECT 3,'AAA','BBB','2008-01-01','2012-02-02' UNION ALL
         SELECT 4,'AAA','BBB','2002-01-01','2004-01-01' UNION ALL
         SELECT 5,'DDD','EEE','2009-01-01','2012-01-01' UNION ALL
         SELECT 6,'DDD','EEE','2011-01-01','2020-01-01' UNION ALL
         SELECT 7,'DDD','EEE','2013-01-01','2015-01-01' UNION ALL
         SELECT 8,'DDD','EFG','2009-01-01','2012-01-01'    ),
     RecursiveCTE
     AS (SELECT id,
                match1,
                match2,
                startdate,
                enddate,
                CAST(NULL AS VARCHAR(4)) AS Status,
                enddate                  AS LastSuccessfulEnd
         FROM   (SELECT *,
                        ROW_NUMBER() OVER (PARTITION BY match1, match2 
                                               ORDER BY startdate) RN
                 FROM   BaseData) B
         WHERE  RN = 1
         UNION ALL
         SELECT id,
                match1,
                match2,
                startdate,
                enddate,
                Status,
                LastSuccessfulEnd
         FROM   (
                SELECT B.*,
                       rn = ROW_NUMBER() OVER (PARTITION BY B.match1, B.match2 
                                                   ORDER BY B.startdate),
                       CASE
                         WHEN B.startdate < R.LastSuccessfulEnd THEN 'FAIL'
                       END AS Status,
                       CASE
                         WHEN B.startdate >= R.LastSuccessfulEnd THEN B.enddate
                         ELSE R.enddate
                       END AS LastSuccessfulEnd
                 FROM   BaseData B
                        JOIN RecursiveCTE R
                          ON R.match1 = B.match1
                             AND R.match2 = B.match2
                             AND B.startdate > R.startdate) R
         WHERE  R.rn = 1)
SELECT id,
       match1,
       match2,
       startdate,
       enddate,
       Status
FROM   RecursiveCTE
ORDER  BY id 
于 2011-12-29T00:38:09.353 回答