我很难想出一种基于日期范围加入/合并两个表的方法来创建一个包含一个时间线的表。
使用一些示例数据删除表格的版本:
Table 1
---------------------------------
ID Start End State
1 10:00 10:05 A
2 10:23 10:24 B
3 10:32 10:40 A
4 14:00 14:15 C
Table 2
---------------------------------
ID Start End State
1 10:22 10:27 X
2 11:00 11:20 Y
3 12:05 14:30 Z
这两个表由两个不同的进程维护,虽然每个表中的事件永远不会重叠,但两个表之间可能会有重叠。
第一个表中的事件应优先于第二个表中的事件。也就是说,基本上从第一个选择所有内容并用第二个填充空白。
基于上面的示例,预期的查询输出将是:
Start End State
10:00 10:05 A
10:22 10:23 X
10:23 10:24 B
10:24 10:27 X
10:32 10:40 A
11:00 11:20 Y
12:05 14:00 Z
14:00 14:15 C
14:15 14:30 Z
注意表2中的状态Z是如何从表1中的状态C分割出来的。
我看到了一些基于单个时间戳加入表的示例,或者可能是一个具有日期范围的表和另一个具有单个时间戳的表。我还没有看到这种性质的东西,而且由于我的经验水平相当基本,我的想法是围成一圈的。
感谢您的任何建议,如果我想出任何突破,我一定会更新。
更新
感谢Gordon,这是我正在使用的解决方案(他的内容略有修改版本):
---------------------------------------------------------------------------------------------
-- Setup Table 1 --
---------------------------------------------------------------------------------------------
DECLARE @Table1 TABLE(ID INT, Start DATETIMEOFFSET(7), [End] DATETIMEOFFSET(7), [State] CHAR)
INSERT @Table1
VALUES (1, '2013-12-21 10:00:00 +00:00', '2013-12-21 10:05:00 +00:00', 'A'),
(2, '2013-12-21 10:23:00 +00:00', '2013-12-21 10:24:00 +00:00', 'B'),
(3, '2013-12-21 10:32:00 +00:00', '2013-12-21 10:40:00 +00:00', 'A'),
(4, '2013-12-21 14:00:00 +00:00', '2013-12-21 14:15:00 +00:00', 'C')
SELECT * FROM @Table1
---------------------------------------------------------------------------------------------
-- Setup Table 2 --
---------------------------------------------------------------------------------------------
DECLARE @Table2 TABLE (ID INT, Start DATETIMEOFFSET(7), [End] DATETIMEOFFSET(7), [State] CHAR)
INSERT @Table2
VALUES (1, '2013-12-21 10:22:00 +00:00', '2013-12-21 10:27:00 +00:00', 'X'),
(2, '2013-12-21 11:00:00 +00:00', '2013-12-21 11:20:00 +00:00', 'Y'),
(3, '2013-12-21 12:05:00 +00:00', '2013-12-21 14:30:00 +00:00', 'Z')
SELECT * FROM @Table2
---------------------------------------------------------------------------------------------
-- Merge Tables --
---------------------------------------------------------------------------------------------
;WITH StateChangeTimes AS (
SELECT DISTINCT TheTime
FROM (SELECT T1.Start AS TheTime, T1.[State]
FROM @Table1 T1
UNION ALL
SELECT T1.[End], NULL
FROM @Table1 T1
UNION ALL
SELECT T2.Start, T2.[State]
FROM @Table2 T2
UNION ALL
SELECT T2.[End], NULL
FROM @Table2 T2) T ),
TimePairs AS (
SELECT TheTime AS Start,
(SELECT MIN(SCT2.TheTime)
FROM StateChangeTimes SCT2
WHERE SCT2.thetime > SCT.TheTime) AS [End]
FROM StateChangeTimes SCT)
SELECT Start,
[End],
COALESCE(T1State, T2State) AS [State]
FROM (SELECT Start,
[End],
(SELECT TOP 1
T1.[State]
FROM @Table1 T1
WHERE TP.Start >= T1.Start AND TP.[End] <= T1.[End]
ORDER BY T1.Start DESC) T1State,
(SELECT TOP 1
T2.[State]
FROM @Table2 T2
WHERE TP.Start >= T2.Start AND TP.[End] <= T2.[End]
ORDER BY T2.Start DESC) T2State
FROM TimePairs TP) TP2
ORDER BY Start;
我做出的主要改变:
在抓取合并状态的select语句的where子句中,我将结束时间戳包含在内。
在TOP 1限定符中添加到第一个项目符号中提到的第一个状态选择语句。
答案 0 :(得分:3)
我认为这是一个难题。
这是我正在考虑的方式。获取所有开始和结束时间的列表。这为不同的时间段提供了“边界”。接下来,在每个时间段内查找状态。
特定时期的国家规则是:
(规则2实际上包含规则1.)
下一个问题是在SQL中实现这一点。方法是获取各个时间段,将它们组合成对,然后进行查找。由于SQL Server 2008缺少lag()
和累积总和(在SQL Server 2012中)等功能,因此代码使用相关的子查询。
with StateChangeTimes as (
select distinct thetime
from (select start as thetime, state
from Table1 t1
union all
select end, NULL
from Table1 t1
union all
select start, state
from Table2 t2
union all
select end, NULL
from Table2 t2
) t
),
timepairs as (
select thetime as start,
(select min(thetime)
from StateChangeTimes sct2
where sct2.thetime > sct.thetime
) as end
from StateChangeTimes sct
)
select start, end, coalesce(t1State, t2State) as state
from (select start, end,
(select t1.state
from Table1 t1
where tp.start >= t1.start and tp.end < t1.end
) t1State,
(select t2.state
from Table2 t2
where t2.start <= tp.start
order by t2.start desc
) t2State
from timepairs tp
) tp
order by start;
我不确定当两个表中同时出现时此代码是否有效。此外,如果Table1次重叠,它将生成错误。这是相对容易修复的,但似乎并不是必需的。