根据复合键检查重叠的日期范围

时间:2014-06-03 14:54:11

标签: sql sql-server join

我有一个SQL Server 2008表,其数据如下:

Contract_No  Property_No  Start_Dte     End_Dte
12345        123          01/01/2014    01/31/2014
12345        123          01/15/2014    02/15/2014
12345        123          03/01/2014    03/31/2014
12345        124          01/01/2014    01/31/2014

我不能拥有重叠日期范围的相同合约/物业#。因此,上面的第二行将是一个问题,因为它的Start_Dte在第一行的日期范围的中间开始。所有其他行都没问题。

我真的对如何使用SQL查询执行此操作感到茫然。我知道如何使用像C#或VB这样的语言来检查这一点,但是我写的查询失败了。

有人有什么想法吗?

3 个答案:

答案 0 :(得分:2)

以下查询将显示与其他记录(SQL Fiddle)存在冲突的日期范围的所有记录:

WITH x AS (
  SELECT *,ROW_NUMBER() OVER (ORDER BY Contract_No, Property_No, Start_Dte) AS r
  FROM MyTable
)
SELECT * 
FROM x m1
INNER JOIN x m2
ON m2.Contract_No = m1.Contract_No
AND m2.Property_No = m1.Property_No
AND m1.r <> m2.r
AND 
(  
  (
    m2.Start_Dte >= m1.Start_Dte 
    AND m2.Start_Dte <= m1.End_Dte
  ) OR 
  (
    m2.End_Dte >= m1.Start_Dte 
    AND m2.End_Dte <= m1.End_Dte
  )
)

答案 1 :(得分:1)

(编辑)的

以下查询将生成一个合约/属性对列表,其中有两个或更多重叠句点:

SELECT distinct t1.Contract_No, t1.Property_No, t1.Start_Dte, t1.End_Dte
 from MyTable t1
  inner join MyTable t2
   on t2.Contract_No = t1.Contract_No
    and t2.Property_No = t1.Property_No
    and t1.Start_Dte <> t2.Start_Dte  --  PK check
    and t1.End_Dte <> t2.End_Dte      --  PK check
    and t2.Start_Dte < t1.End_Dte
    and t2.End_Dte > t1.Start_Dte

这对提供的样本数据起作用,但可能还有一些需要考虑的边缘情况,例如......

难看的难点在于,如果没有引用每一列,就无法唯一地识别表中的行...这意味着如果两行或多行具有相同的时间,则此查询不会捕获它们,并且您需要使用使用row-number的其他解决方案之一。 (当然,没有主键,你也会遇到很多其他问题......)如果有可用的主键,可以用简单的主键检查替换两个-- PKcheck行。

如上所述,我第一次没有得到这个Aztec Math的东西。以下是我最初的预调试响应。


以下查询将生成一个合约/属性对列表,其中有两个或更多重叠句点:

SELECT distinct t1.Contract_No, t1.Property_No
 from MyTable t1
  inner join MyTable t2
   on t2.Contract_No = t1.Contract_No
    and t2.Property_No = t1.Property_No
    and (t2.Start_Dte > t1.End_Dte
         or t2.End_Dte < t1.Start_Dte)

一定要测试逻辑,我总是发现在第一时间完全正确地获取这些时间查询很棘手。这个想法是

  • 第二份合约在第一份合约结束后开始
  • 或者第二份合同在第一份合同开始之前结束
  • 如果其中一个不适用,则期间将重叠

如果开始/停止日期可能重叠,请使用&gt; =和&lt; =。如果您使用的是datetime或smalldatetime数据类型,请小心 - 除了日期之外,您还将在值中有一个时间“元素”。

那是开始。下一步是列出所有合同/属性:

SELECT tt.*  --  Being lazy here, you should always specify precisely which columns to return
 from MyTable tt
  inner join (--  Make it a subquery
              select distinct t1.Contract_No, t1.Property_No
                from MyTable t1
                inner join MyTable t2
                 on t2.Contract_No = t1.Contract_No
                  and t2.Property_No = t1.Property_No
                  and (t2.Start_Dte > t1.End_Dte
                       or t2.End_Dte < t1.Start_Dte)) xx
   on xx.Contract_No = tt.Contract_No
    and xx.Property_No = tt.Property_No

接下来:确定合同错误。当然,这需要应用商业逻辑,将球放回你的球场。

答案 2 :(得分:1)

请试试这个

WITH cte AS (
  SELECT *,ROW_NUMBER() OVER (ORDER BY [Contract_No], [Property_No], [Start_Dte]) AS row_num
  FROM tbl
)
SELECT *
FROM cte t1
WHERE EXISTS(
  SELECT 1 
  FROM cte t2 
  WHERE 
   t1.Contract_No = t2.Contract_No
  AND t1.Property_No = t2.Property_No
  AND t1.row_num > t2.row_num
  AND (
      (t1.Start_Dte BETWEEN t2.Start_Dte AND t2.End_Dte)
        OR 
      (t1.END_Dte BETWEEN t2.Start_Dte AND t2.End_Dte)
  )
)

SQL Fiddle Demo