查询以合并连续的时间记录

时间:2011-09-22 19:47:36

标签: sql-server-2005

我有一张这样的表:

id     START_DATE   end_date
1      01/01/2011   01/10/2011
2      01/11/2011   01/20/2011
3      01/25/2011   02/01/2011
4      02/10/2011   02/15/2011
5      02/16/2011   02/27/2011

我想合并start_date刚好是另一条记录的end_date的第二天的记录:所以结束记录应该是这样的:

new_id     START_DATE   end_date
1         01/01/2011   01/20/2011
2         01/25/2011   02/01/2011
3         02/10/2011   02/27/2011

我知道这样做的一种方法是创建一个基于行的临时表,其中各行作为日期(一个日期的每个记录,在总天数范围内),从而使表格变平。

但是必须有更简洁的方法在单个查询中执行此操作...例如使用row_num的东西?

谢谢你们。

4 个答案:

答案 0 :(得分:0)

试试这个

  Declare @chgRecs Table 
      (updId int primary key not null,
       delId int not null,
       endt datetime not null)
  While Exists (Select * from Table a
                Where Exists 
                    (Select * from table
                     Where start_date = 
                         DateAdd(day, 1, a.End_Date))) 
  Begin
      Insert @chgRecs (updId, delId , endt)
      Select a.id, b.id, b.End_Date, 
      From table a 
      Where Exists 
          (Select * from table
           Where start_date = 
              DateAdd(day, 1, a.End_Date)))
         And Not Exists
             (Select * from table
              Where end_Date = 
                 DateAdd(day, -1, a.Start_Date)))

      Delete table Where id In (Select delId from @chgRecs ) 
      Update table set
          End_Date = u.endt
      From table t join @chgRecs u 
          On u.updId = t.Id
      Delete @delRecs
  End

答案 1 :(得分:0)

不,不是在寻找一个循环...

我想这是一个很好的解决方案:

获取#temp表中的所有数据

SELECT * FROM #temp
SELECT t2.start_date , t1.end_date FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date)
UNION
SELECT START_DATE,end_date FROM #temp WHERE start_date NOT IN  (SELECT t2.START_DATE FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date))
AND end_date NOT IN (SELECT t1.end_Date FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date))
DROP TABLE #temp

如果有什么比这更好的话,请告诉我。

谢谢你们。

答案 2 :(得分:0)

declare @T table
(
  id int,
  start_date datetime,
  end_date datetime
)

insert into @T values
(1,      '01/01/2011',   '01/10/2011'),
(2,      '01/11/2011',   '01/20/2011'),
(3,      '01/25/2011',   '02/01/2011'),
(4,      '02/10/2011',   '02/15/2011'),
(5,      '02/16/2011',   '02/27/2011')

select row_number() over(order by min(dt)) as new_id,
       min(dt) as start_date,
       max(dt) as end_date
from (
      select dateadd(day, N.Number, start_date) as dt,
             dateadd(day, N.Number - row_number() over(order by dateadd(day, N.Number, start_date)), start_date) as grp
      from @T
        inner join master..spt_values as N
          on N.number between 0 and datediff(day, start_date, end_date) and
             N.type = 'P'
     ) as T
group by grp
order by new_id        

您可以使用numbers table代替master..spt_values

答案 3 :(得分:0)

递归解决方案:

CREATE TABLE TestData
(
  Id INT PRIMARY KEY,
  StartDate DATETIME NOT NULL,
  EndDate DATETIME NOT NULL
);
SET DATEFORMAT MDY;
INSERT  TestData 
SELECT  1,      '01/01/2011',   '01/10/2011'
UNION ALL
SELECT  2,      '01/11/2011',   '01/20/2011'
UNION ALL
SELECT  3,      '01/25/2011',   '02/01/2011'
UNION ALL
SELECT  4,      '02/10/2011',   '02/15/2011'
UNION ALL
SELECT  5,      '02/16/2011',   '02/27/2011'
UNION ALL
SELECT  6,      '02/28/2011',   '03/06/2011'
UNION ALL
SELECT  7,      '02/28/2011',   '03/03/2011'
UNION ALL
SELECT  8,      '03/10/2011',   '03/18/2011'
UNION ALL
SELECT  9,      '03/19/2011',   '03/25/2011';

WITH RecursiveCTE
AS
(
    SELECT  t.Id, t.StartDate, t.EndDate
            ,1 AS GroupID
    FROM    TestData t
    WHERE   t.Id=1
    UNION ALL
    SELECT  crt.Id, crt.StartDate, crt.EndDate
            ,CASE WHEN DATEDIFF(DAY,prev.EndDate,crt.StartDate)=1 THEN prev.GroupID ELSE prev.GroupID+1 END
    FROM    TestData crt
    JOIN    RecursiveCTE prev ON crt.Id-1=prev.Id
    --WHERE crt.Id > 1  
)
SELECT  cte.GroupID, MIN(cte.StartDate) AS StartDate, MAX(cte.EndDate) AS EndDate
FROM    RecursiveCTE cte
GROUP BY cte.GroupID
ORDER BY cte.GroupID;

DROP TABLE TestData;