如果相邻期间之间的差异小于x(例如x = 3)天,如何合并日期期间。在下面的示例中,期间3的开始日期和期间2的结束日期之间的差异为2.So第三期和第二期合并为单期,如下所示。但期间4的开始日期与期间3的结束日期之间的差异为3.因此,它们不会合并并作为单独的期间处理。
startdate enddate
-------------------------------------------------------
2004-12-29 00:00:00.000 2004-12-29 00:00:00.000
2005-11-25 00:00:00.000 2005-11-25 00:00:00.000
2005-11-27 00:00:00.000 2005-12-09 00:00:00.000
2005-12-12 00:00:00.000 2005-12-17 00:00:00.000
2005-12-19 00:00:00.000 2005-12-20 00:00:00.000
输出:
startdate enddate
---------------------------------------------------------
2004-12-29 00:00:00.000 2004-12-29 00:00:00.000
2005-11-25 00:00:00.000 2005-12-09 00:00:00.000
2005-12-12 00:00:00.000 2005-12-20 00:00:00.000
答案 0 :(得分:1)
set dateformat dmy;
declare @t table (id int identity, startdate smalldatetime, enddate smalldatetime);
insert into @t (startdate, enddate) values ('02.01.2015', '03.01.2015');
insert into @t (startdate, enddate) values ('06.01.2015', '06.01.2015');
insert into @t (startdate, enddate) values ('10.01.2015', '11.01.2015');
declare @x int = 3;
declare @toDel table(id int);
update
a
set
a.enddate = b.enddate
output
b.id
-- save merged id, than should be deleted
into
@toDel (id)
from
@t a
join @t b on datediff(day, a.enddate, b.startdate) between 0 and @x
and a.id != b.id
;
-- delete merged id
delete from @t where id in (select d.id from @toDel d);
select * from @t;
答案 1 :(得分:1)
首先需要识别相邻的记录。对于这些记录,您只需要保留一个具有组合日期范围的记录,其他记录可以简单地传递:
;WITH adjacent
AS ( SELECT a.startdate AS startDateA ,
a.enddate AS endDateA ,
b.startdate AS startDateB ,
b.enddate AS endDateB
FROM dbo.data a
LEFT JOIN dbo.data b ON DATEDIFF(day, a.enddate,
b.startdate) <= 3
AND a.startdate < b.startdate
)
SELECT a.startDateA AS StartDate ,
ISNULL(a.endDateB, a.endDateA) AS EndDate
FROM adjacent a
LEFT JOIN adjacent b ON a.startDateA = b.startDateB
AND a.endDateA = b.endDateB
WHERE b.startDateA IS NULL
ORDER BY a.startDateA
这是我用过的测试脚本:
CREATE TABLE dbo.data(startdate DATETIME, enddate DATETIME)
INSERT INTO dbo.data
SELECT '2 Jan 2015' ,
'3 Jan 2015'
UNION
SELECT '6 Jan 2015' ,
'6 Jan 2015'
UNION
SELECT '10 Jan 2015' ,
'11 Jan 2015'
编辑:如果您需要在函数中合并多个日期范围(例如x = 10),则上述解决方案将无效,您必须使用下面的递归cte。根据你的评论,我还在一个函数中重构了这段代码:
CREATE TYPE daterangetype AS TABLE
(
startdate DATETIME NOT NULL,
enddate DATETIME NOT NULL
)
GO
CREATE FUNCTION dbo.fn_Merge_DateRanges
(
@data daterangetype READONLY ,
@dayrange INT
)
RETURNS @merged TABLE
(
startdate DATETIME ,
endate DATETIME
)
AS
BEGIN
WITH cte0
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY startdate ) AS RowId ,
startdate ,
enddate
FROM @data
),
cte1
AS ( SELECT t.RowId ,
t.startdate ,
t.enddate ,
t2.startdate AS Nextstartdate
FROM cte0 AS t
LEFT OUTER JOIN cte0 AS t2 ON t2.RowId > t.RowId
AND DATEDIFF(day,
t.enddate,
t2.startdate) < @dayrange
),
cte2
AS ( SELECT c.RowId ,
c.startdate ,
c.enddate ,
c.Nextstartdate
FROM cte1 AS c
WHERE c.Nextstartdate IS NULL
UNION ALL
SELECT c2.RowId ,
c.startdate ,
c2.enddate ,
c2.Nextstartdate
FROM cte2 AS c2
INNER JOIN cte1 AS c ON c.Nextstartdate = c2.startdate
)
INSERT INTO @merged
SELECT MIN(startdate) AS startdate ,
enddate
FROM cte2
GROUP BY RowId ,
enddate
ORDER BY RowId ,
startdate
RETURN
END
然后你可以这样调用你的函数:
DECLARE @data daterangetype
SET DATEFORMAT YMD
INSERT INTO @data
SELECT '2004-12-29 00:00:00.000' ,
'2004-12-29 00:00:00.000'
UNION ALL
SELECT '2005-11-25 00:00:00.000' ,
'2005-11-25 00:00:00.000'
UNION ALL
SELECT '2005-11-27 00:00:00.000' ,
'2005-12-09 00:00:00.000'
UNION ALL
SELECT '2005-12-12 00:00:00.000' ,
'2005-12-17 00:00:00.000'
UNION ALL
SELECT '2005-12-19 00:00:00.000' ,
'2005-12-20 00:00:00.000'
SELECT * FROM dbo.fn_Merge_DateRanges(@data, 5)