我有下表:
startDate endDate
----------------------
01-01-2014 01-07-2014
01-08-2014 01-14-2014
01-15-2014 01-21-2014
01-28-2014 02-03-2014
02-04-2014 02-10-2014
我想将日期捆绑在一起以最小化记录数量。输出结果应如下所示:
startDate endDate
----------------------
01-01-2014 01-21-2014
01-28-2014 02-10-2014
如果一条记录的startDate比另一条记录的endDate晚一天,则日期可以链接在一起。
这可以在不使用游标的情况下实现吗?
答案 0 :(得分:3)
正如评论中所述,您需要Recursive CTE
加Window Function
来汇总连续的天数
;WITH cte
AS (SELECT StartDate,
EndDate
FROM yourtable
UNION ALL
SELECT a.StartDate,
b.EndDate
FROM cte a
JOIN yourtable b
ON Dateadd(DAY, 1, a.EndDate) = b.StartDate),
cte1
AS (SELECT StartDate,
EndDate,
Row_number()
OVER(
partition BY EndDate
ORDER BY StartDate ASC) AS rn
FROM cte)
SELECT StartDate,
Max(EndDate) AS EndDate
FROM cte1 a
WHERE a.rn = 1
GROUP BY StartDate
ORDER BY EndDate
答案 1 :(得分:3)
注意:以下代码与SQL Server 2012兼容
使用以下代码:
SELECT MIN(startdate), MAX(enddate)
FROM
(
SELECT *, SUM(diff) OVER(ORDER BY startdate) AS cat FROM
(
SELECT
startdate,
endDate,
CASE WHEN DATEDIFF("dd", LAG(enddate) OVER (ORDER BY startdate), startdate) > 1 THEN 1 ELSE 0 END AS diff
FROM <Your Table>
) t
) t
GROUP BY cat
发生了什么事?
上面的代码使用窗口函数来检测上一个结束日期并检查它与当前开始日期之间的差异,如果存在差异则放置1,否则放置0。结果表应如下所示:
startdate enddate diff
2014-01-01 2014-01-07 0
2014-01-08 2014-01-14 0
2014-01-15 2014-01-21 0
2014-01-28 2014-02-03 1
2014-02-04 2014-02-10 0
2014-02-11 2014-03-04 0
2014-03-14 2014-03-21 1
2014-04-01 2014-05-10 1
使用SUM
函数作为窗函数从当前行到第一行求和,结果为:
startdate endDate diff cat
2014-01-01 2014-01-07 0 0
2014-01-08 2014-01-14 0 0
2014-01-15 2014-01-21 0 0
2014-01-28 2014-02-03 1 1
2014-02-04 2014-02-10 0 1
2014-02-11 2014-03-04 0 1
2014-03-14 2014-03-21 1 2
2014-04-01 2014-05-10 1 3
然后,您可以通过为每个MIN(startdate)
获取MAX(enddate)
和cat
来轻松汇总这些内容。
答案 2 :(得分:1)
您可以在没有递归CTE的情况下执行此操作。您只需要识别开始每个序列的记录,然后使用聚合。
with cte as (
select t.*, (case when tprev.startdate is null then 1 else 0 end) as IsSeqStart
from table t left join
table tprev
on t.startdate = dateadd(day, 1, tprev.enddate)
)
select min(startdate) as startdate, max(enddate) as enddate
from (select cte.*, sum(isSeqStart) over (order by startdate) as grp
from cte
) t
group by grp
答案 3 :(得分:1)
此解决方案假设连续日期范围可能重叠
declare @t table (startDate date, endDate date)
insert into @t
values
('01-01-2014', '01-07-2014'),
('01-08-2014', '01-14-2014'),
('01-15-2014', '01-21-2014'),
('01-28-2014', '02-03-2014'),
('02-04-2014', '02-10-2014')
;with cte
as (select startdate, enddate from @t
union all
select cte.startdate, t.enddate
from cte
inner join @t t
on t.startdate between dateadd(dd,1,cte.startDate) and dateadd(dd,1,cte.enddate)
and t.endDate > cte.endDate
)
select min(startdate) startdate, enddate
from
(select startDate, max(enddate) enddate
from cte
group by startdate) a
group by enddate
答案 4 :(得分:1)
您也可以尝试以下方法
;WITH cte AS
(
SELECT ROW_NUMBER() OVER(ORDER BY t1.startDate) AS Id, t1.StartDate
FROM dbo.test104 t1 LEFT JOIN dbo.test104 t2 ON DATEADD(DAY, -1, t1.startDate) = t2.endDate
WHERE t2.endDate IS NULL
), cte2 AS
(
SELECT ROW_NUMBER() OVER(ORDER BY t1.EndDate) AS Id, t1.EndDate
FROM dbo.test104 t1 LEFT JOIN dbo.test104 t2 ON DATEADD(DAY, 1, t1.EndDate) = t2.StartDate
WHERE t2.startDate IS NULL
)
SELECT *
FROM cte c1 JOIN cte2 c2 ON c1.Id = c2.Id