2011-09-22 70 views
3

我有这样的一个表:查询合并连续时间记录

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 

我要合并的记录中,其中起始日期是另一个纪录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的东西?

谢谢你们。

回答

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

+0

这个工作就像魅力。只有一个问题:什么是master..spt_values? – Tintin

+0

@ user503510 - 这是SQL Server中的系统表。 http://stackoverflow.com/questions/4273723/what-is-the-purpose-of-system-table-table-master-spt-values-and-what-are-the-mea –

+0

@ user503510 - 最大数量在master..spt_values是2048,所以如果你期望有一个连续的日期范围,那么你需要一个数字表来代替。 –

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 
+0

多部分标识符 “b.id” 不能被约束。 – Tintin

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 

请让我知道是否有比这更好的东西。

谢谢你们。

+0

但是这个工作一次只合并两行......因此这将不起作用......将尝试查尔斯所建议的(虽然我不想使用循环)... – Tintin

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;