【问题标题】:Dates overlapping scenario日期重叠场景
【发布时间】:2011-12-19 21:31:40
【问题描述】:

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

id match1  match2  match3  startdate   enddate
1  AAA     BBB     CCC     2006-01-01  2007-01-01 
2  AAA     BBB     CCC     2006-12-12  2008-01-01
3  AAA     BBB     CCC     2008-01-01  2012-02-02

4  DDD     EEE     FFF     2009-01-01  2012-01-01
5  DDD     EEE     FFF     2013-01-01  2020-01-01

Ref TableB (match1 char, match2, match3, startdate datetime, enddate)

match1  match2 match3  startdate   enddate
AAA     BBB    CCC     2006-01-01  2015-01-01
DDD     EEE    FFF     2009-01-01  2015-01-01

好的,所以 [Stat] 为 NULL,我必须在 tableA 中使用 'FAIL' 填充 stat:

1) 匹配tableB中的match1,match2,match3,日期(开始和结束)在范围之外。让我们看看 ID=5 有效日期 = 2013 - 2020,但在它的参考表中,它的 2009-2015 所以 ID = 5 得到“失败”。

2) 在集合中,集合是 match1、match2、match3 相等的记录,因此 ID 123 是一个集合,ID 4&5 是另一个集合。因此,在一组中,生效日期(开始和结束)日期重叠。即使集合 1 (ID1,2,3) 存在于引用表中其对应记录的日期范围内,但 ID = 2 的生效日期与 ID = 1 的生效日期重叠,因此 ID = 2 得到'FAIL'

预期结果:

id match1  match2  match3  startdate   enddate     stat
1  AAA     BBB     CCC     2006-01-01  2007-01-01  NULL
2  AAA     BBB     CCC     2006-12-12  2008-01-01  FAIL
3  AAA     BBB     CCC     2008-01-01  2012-02-02  NULL
4  DDD     EEE     FFF     2009-01-01  2012-01-01  NULL
5  DDD     EEE     FFF     2013-01-01  2020-01-01  FAIL

提前致谢。

【问题讨论】:

  • 将第一个视为 ok 并“失败”下一个重叠。
  • 在 ID 1 和 2 重叠的第二种情况下,您如何决定“失败” ID 为 2 的行而不是 ID 为 1 的行?在这种情况下,您是否总是使开始日期较晚的行失败?

标签: sql datetime


【解决方案1】:
UPDATE tableA SET [status] = 'FAIL'
FROM tableB 
WHERE tableB.match1 = tableA.match1 
AND tableB.match2 = tableA.match2 
AND tableB.match3 = tableA.match3
AND tableA.startDate >= tableB.startDate 
AND tableA.endDate <= tableB.endDate

编辑(我认为我可能过于简单化了) EDIT2 - 更改第二个 WHERE

SELECT  --  Things outside of allowed date range
id 
FROM TableA 
JOIN TableB ON TableB.match1 = TableA.match1 
    AND TableB.match2 = TableA.match2
    AND TableB.match3 = TableA.match3 
WHERE TableA.startDate < TableB.startDate 
    OR TableA.endDate > TableB.endDate 
UNION 
SELECT  --  Things with overlapping date ranges
TableA2.id 
FROM TableA    
JOIN TableA AS TableA2 ON TableA2.match1 = TableA.match1
    AND TableA2.match2 = TableA.match2      
    AND TableA2.match3 = TableA.match3    
WHERE TableA2.startDate BETWEEN TableA.startDate AND TableA.endDate 
    OR TableA2.endDate BETWEEN TableA.startDate AND TableA.endDate
    OR (TableA2.startDate < TableA.startDate AND TableA2.endDate > TableA.endDate)

【讨论】:

  • ANDREW:您的代码在 ID 1、2、3、4 失败,而它应该只在 2 和 5 失败。
  • 另外,我们必须在 [set] 中将 enddate od id1 与 id2 的 startdate 等进行匹配,您的代码似乎没有这样做。谢谢
  • 对不起,我在这里发现了case1的另一个漏洞。假设 ids 1 2 3 日期是 2006-2008, 2012-2014, 2009-2010 。现在即使日期不相互重叠并且存在于其参考记录的范围内,它仍然会失败 id=3 因为 TableA2.startDate
【解决方案2】:

SQL 语句

;WITH CandidateIDs AS (
    SELECT  idOriginal = YourTable.id, idFailCandidate = ed.id
    FROM    YourTable
            INNER JOIN YourTable ed ON ed.match1 = YourTable.match1
                               AND ed.match2 = YourTable.match2
                               AND ed.startdate BETWEEN YourTable.startdate AND YourTable.enddate
                               AND ed.id <> YourTable.id
)                              
SELECT  *
FROM    YourTable
        INNER JOIN (
            SELECT  idFailCandidate
            FROM    CandidateIDs r1
            WHERE   NOT EXISTS (SELECT * FROM CandidateIDs WHERE CandidateIDs.idFailCandidate = r1.idOriginal)
        ) fail ON fail.idFailCandidate = YourTable.id           

测试脚本

;WITH YourTable (id, match1, match2, startdate, enddate, status) AS (
    SELECT 1, 'AAA', 'BBB', CAST('2006-01-01' AS DATETIME), CAST('2007-01-01' AS DATETIME), NULL
    UNION ALL SELECT 2, 'AAA', 'BBB', '2006-12-12', '2008-01-01', NULL
    UNION ALL SELECT 3, 'AAA', 'BBB', '2008-01-01', '2012-02-01', NULL
    UNION ALL SELECT 4, 'AAA', 'BBB', '2002-01-01', '2004-01-01', NULL
    UNION ALL SELECT 5, 'DDD', 'EEE', '2009-01-01', '2012-01-01', NULL
    UNION ALL SELECT 6, 'DDD', 'EEE', '2011-01-01', '2020-01-01', NULL
    UNION ALL SELECT 7, 'DDD', 'EEE', '2013-01-01', '2015-01-01', NULL
    UNION ALL SELECT 8, 'DDD', 'EFG', '2009-01-01', '2012-01-01', NULL
)
, CandidateIDs AS (
    SELECT  idOriginal = YourTable.id, idFailCandidate = ed.id
    FROM    YourTable
            INNER JOIN YourTable ed ON ed.match1 = YourTable.match1
                               AND ed.match2 = YourTable.match2
                               AND ed.startdate BETWEEN YourTable.startdate AND YourTable.enddate
                               AND ed.id <> YourTable.id
)                              
SELECT  *
FROM    YourTable
        INNER JOIN (
            SELECT  idFailCandidate
            FROM    CandidateIDs r1
            WHERE   NOT EXISTS (SELECT * FROM CandidateIDs WHERE CandidateIDs.idFailCandidate = r1.idOriginal)
        ) fail ON fail.idFailCandidate = YourTable.id           

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多