查找多行中连续日期的开始和结束日期
Posted
技术标签:
【中文标题】查找多行中连续日期的开始和结束日期【英文标题】:find start and stop date for contiguous dates in multiple rows 【发布时间】:2014-06-18 15:50:38 【问题描述】:我在显示表格中的正确数据时遇到了一些问题。 我也不确定要搜索什么。 我不确定 min(column) 或 max(column) 是否会帮助我。让我们看看我是否可以解释我的问题。
我的表包含以下数据:
> Code (nvarchar) | DateFrom (datetime) | DateTo (datetime)
> =========================================================
> 3006 | 2014-06-18 07:00:00 | 2014-06-18 08:00:00
> 3006 | 2014-06-18 09:00:00 | 2014-06-18 22:00:00
> 1006 | 2014-06-18 07:00:00 | 2014-06-18 09:00:00
> 1006 | 2014-06-18 08:00:00 | 2014-06-18 08:30:00
> 1006 | 2014-06-18 08:10:00 | 2014-06-18 18:00:00
我将通过一个视图来介绍这一点。 它将按代码分组。
我想要的是这个输出:
> Code | DateFrom | DateTo
> =========================================================
> 3006 | 2014-06-08 07:00:00 | 2014-06-18 08:00:00
> 3006 | 2014-06-18 09:00:00 | 2014-06-18 22:00:00
> 1006 | 2014-06-18 07:00:00 | 2014-06-18 18:00:00
如您所见,DateTo 和 DateFrom 之间是否存在间隙,我希望它显示为两行。但是,如果下一个具有相同代码的“DateFrom”在 DateTo 结束之前(或同时)开始,我希望改为显示“DateTo”。
在这种情况下,我不知道如何使用函数 max() 或 min()。因为时间段内可能存在间隙。
你们有什么线索吗?
我使用的是 MS SQL 2012
提前致谢!
编辑:如评论。岛屿可能是我的解决方案?
【问题讨论】:
您尝试过使用 LAG() 或 LEAD() Fcts 吗? 不,我没有。我不熟悉那个功能。我会谷歌它。 :) 我不认为这是我需要的。即使 dateto 和 datefrom 之间存在间隔,它也会捕获下一个 dateto。 我认为您想要的称为gaps-and-islands
技术来识别数据中的运行/差距。
那个人可能会以某种方式解决问题。我去看看!
【参考方案1】:
旧答案有一个弱点:每行仅与前一行检查以验证周期是否重叠,如果较早的行有一个持续时间更长的周期,则逻辑不会考虑它。例如:
Code | DateStart | DateFrom | Overlap
-----+---------------------+---------------------+---------
1006 | 2014-06-18 07:00:00 | 2014-06-18 19:00:00 | 0
1006 | 2014-06-18 08:10:00 | 2014-06-18 10:00:00 | 1
1006 | 2014-06-18 16:00:00 | 2014-06-18 20:30:00 | 0 <- don't overlap with
previous but overlap
with the first
要改进 PrevStop
需要变为 LastStop
并具有 Code
的前一个 DateFrom
的最大值
With N AS (
SELECT Code, DateFrom, DateTo
, LastStop = MAX(DateTo)
OVER (PARTITION BY Code ORDER BY DateFrom, DateTo
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
FROM Table1
), B AS (
SELECT Code, DateFrom, DateTo
, Block = SUM(CASE WHEN LastStop Is Null Then 1
WHEN LastStop < DateFrom Then 1
ELSE 0
END)
OVER (PARTITION BY Code ORDER BY DateFrom, LastStop)
FROM N
)
SELECT Code
, MIN(DateFrom) DateFrom
, MAX(DateTo) DateTo
FROM B
GROUP BY Code, Block
ORDER BY Code, Block
SQLFiddle Demo
需要ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
才能从MAX
中删除当前行。
旧答案
此查询仅适用于不完全在先例中的每个句点。
这个想法是检查每一行是否与下一个/上一个链接。
如果行被链接,它们形成一个块,它们将被组合在一起以获得第一个 DateFrom
和最后一个 DateTo
With N AS (
SELECT Code, DateFrom, DateTo
, PrevStop = LAG(DateTo, 1, NULL)
OVER (PARTITION BY Code ORDER BY DateFrom)
FROM Table1
), B AS (
SELECT Code, DateFrom, DateTo
, Block = SUM(CASE WHEN PrevStop Is Null Then 1
WHEN PrevStop < DateFrom Then 1
ELSE 0
END)
OVER (PARTITION BY Code ORDER BY PrevStop)
FROM N
)
SELECT Code
, MIN(DateFrom) DateFrom
, MAX(DateTo) DateTo
FROM B
GROUP BY Code, Block
ORDER BY Code, Block
SQLFiddle demo 添加了一些数据以检查同一代码/天的更多块
块启动器的查询搜索检查每一行是否是代码的第一行 (PrevStop IS NULL
) 或是否在前一行之外 (PrevStop < DateFrom
)。
窗口化的SUM
仅检索ORDER
的前一行,以创建链接数据块的常数值,例如我们将获得的测试数据
Code | DateStart | DateFrom | Starter | Block
-----+---------------------+---------------------+---------+------
1006 | 2014-06-18 07:00:00 | 2014-06-18 09:00:00 | 1 | 1
1006 | 2014-06-18 08:10:00 | 2014-06-18 06:00:00 | 0 | 1
1006 | 2014-06-18 08:00:00 | 2014-06-18 08:30:00 | 0 | 1
1006 | 2014-06-18 07:00:00 | 2014-06-18 07:30:00 | 1 | 2
1006 | 2014-06-18 08:00:00 | 2014-06-18 08:30:00 | 1 | 3
1006 | 2014-06-18 08:10:00 | 2014-06-18 09:00:00 | 0 | 3
3006 | 2014-06-18 07:00:00 | 2014-06-18 08:00:00 | 1 | 1
3006 | 2014-06-18 09:00:00 | 2014-06-18 10:00:00 | 1 | 2
按Code
和Block
分组得到结果
【讨论】:
似乎这并不成功。我得到多行相同的代码,即使它们在同一个时间段内。 似乎问题出现了,因为有超过 1 个具有相同的开始时间? sqlfiddle.com/#!6/a5c59/1以上是关于查找多行中连续日期的开始和结束日期的主要内容,如果未能解决你的问题,请参考以下文章
查找每个员工的项目开始日期和结束日期(即开始日期和结束日期应该是连续的,在天/月/年中没有任何中断)