tsql最好的方法是将记录与开始日期和结束日期合并,之间没有间隙

时间:2012-09-24 22:50:24

标签: sql-server-2008 tsql

我有一个映射表如下:

FirstEntityID int
MappedTo int
BeginDate Date
EndDate Date

并且假设我在表格中有以下记录:

FirstEntityID  MappedTo  BeginDate     EndDate 
     1             2     2012-09-01   2012-10-01
     2             3     2012-09-01   2012-10-01
     1             2     2012-10-02   2012-11-24
     2             3     2012-11-01   2012-11-24

我需要一个脚本来获取此表并根据开始日期和结束日期合并记录以返回如下结果:

   FirstEntityID  MappedTo  BeginDate     EndDate 
     1             2     2012-09-01   2012-11-24
     2             3     2012-09-01   2012-10-01
     2             3     2012-11-01   2012-11-24

3 个答案:

答案 0 :(得分:3)

使用CTE,我们首先找到开始日期:

; WITH StartD AS
  ( SELECT 
        FirstEntityID
      , MappedTo
      , BeginDate
      , ROW_NUMBER() OVER( PARTITION BY FirstEntityID, MappedTo
                           ORDER BY BeginDate )
          AS Rn 
    FROM
        tableX AS t
    WHERE
        NOT EXISTS
        ( SELECT *
          FROM tableX AS p
          WHERE p.FirstEntityID = t.FirstEntityID
            AND p.MappedTo = t.MappedTo
            AND p.BeginDate < t.BeginDate 
            AND t.BeginDate <= DATEADD(day, 1, p.EndDate)
        )
  )

然后是结束日期:

, EndD AS
  ( SELECT 
        FirstEntityID
      , MappedTo
      , EndDate
      , ROW_NUMBER() OVER( PARTITION BY FirstEntityID, MappedTo
                           ORDER BY EndDate )
          AS Rn 
    FROM
        tableX AS t
    WHERE
        NOT EXISTS
        ( SELECT *
          FROM tableX AS p
          WHERE p.FirstEntityID = t.FirstEntityID
            AND p.MappedTo = t.MappedTo
            AND DATEADD(day, -1, p.BeginDate) <= t.EndDate
            AND t.EndDate < p.EndDate
        )
  )

和最终结果:

SELECT
    s.FirstEntityID
  , s.MappedTo
  , s.BeginDate
  , e.EndDate
FROM
    StartD AS s
  JOIN
    EndD AS e
      ON  e.FirstEntityID = s.FirstEntityID
      AND e.MappedTo = s.MappedTo
      AND e.Rn = s.Rn ;

SQL-Fiddle

中进行测试

答案 1 :(得分:1)

经过测试,似乎有效

在有重复行的边缘情况下会失败 为此,需要采用像Ypercube这样的RowNumber方法 或者在表上添加约束以强制该行是唯一的。

-- first the overlaps
SELECT T1.FirstEntityId, T1.MappedTo, T1.BeginDate, Max(T2.EndDate) as [EndDate]
FROM tablex as T1
join tablex as T2  
  on  T1.FirstEntityId = T2.FirstEntityId
  and T1.MappedTo = T2.MappedTo
  and T1.EndDate >= T2.BeginDate 
  and T1.EndDate <  T2.EndDate
  and T1.BeginDate <= T2.BeginDate
GROUP BY T1.FirstEntityId, T1.MappedTo, T1.BeginDate  

union

-- add the non overlaps
SELECT T1.FirstEntityId, T1.MappedTo, T1.BeginDate, T1.EndDate
FROM tablex as T1
join tablex as T2  
  on  T1.FirstEntityId = T2.FirstEntityId
  and T1.MappedTo = T2.MappedTo
  and (  T1.EndDate  < T2.BeginDate or T1.BeginDate > T2.EndDate 
   or   (T1.BeginDate  < T2.BeginDate and T1.EndDate > T2.EndDate) )

order by FirstEntityId, MappedTo, BeginDate

答案 2 :(得分:0)

这可能有效:

SELECT FirstEntityId, MappedTo, Min(BeginDate), Max(EndDate)
FROM
    T1
GROUP BY
    FirstEntityId, MappedTo