我正在使用SQL SERVER。我有两个表table1和table2。它们都存储时间间隔,为简单起见,两者都有两个datetime2列,列名为表1的S1和S2,表2的T1和T2,每行S1大于S2,完全为表2。我想计算S2和S1之间的间隔值(如时间轴),并在T1和S2上减去T1和T2的重叠。我试过这个,但不能超过计算的第一部分
DECLARE @x float
SET x=0
SELECT SUM(S1-S2)-x from table1
(set x =(SELECT (T1-T2) FROM table2
WHERE T1>=S1 and T2<=S2));
示例:
S2= 10/25/2012 ; S1= 11/30/2012;
assume that we have three rows in table 2
T2=10/20/2012 , T1=10/28/2012
T2=11/4/2012 , T1=11/8/2012
T2=11/22/2012 , T1=11/30/2012
我想要的是找到S1和S2之间的总分钟数,除了与第二个表T1和T2间隔重叠的分钟数。当T1和T2之间的整个间隔在S1和S2的间隔中时,我的查询适用于第二个表中的第二行。 这个例子有点复杂希望这个例子有帮助
查询工作正常,但当T1或T2中的一个处于S1和S2间隔时,我无法使用查询计算重叠值。我应该运行多个查询吗?这里有什么相似之处?
答案 0 :(得分:2)
我在这个例子中使用SQL Server 2008。 此解决方案假设表T中的所有间隔彼此不重叠。
以下文章详细解释了区间代数,我认为它们是一本非常好的读物。他们也有很好的图表。
http://salman-w.blogspot.com.au/2012/06/sql-query-overlapping-date-ranges.html
http://www.ics.uci.edu/~alspaugh/cls/shr/allen.html
http://stewashton.wordpress.com/2014/03/11/sql-for-date-ranges-gaps-and-overlaps/
我以比原始问题更难以混淆的方式命名列。我添加了一些不重叠的额外间隔,以说明建议的解决方案将其过滤掉。
DECLARE @TableS TABLE (ID int IDENTITY(1,1), DateFromS date, DateToS date);
DECLARE @TableT TABLE (ID int IDENTITY(1,1), DateFromT date, DateToT date);
INSERT INTO @TableS (DateFromS, DateToS) VALUES ('2012-10-25', '2012-11-30');
INSERT INTO @TableS (DateFromS, DateToS) VALUES ('2015-10-25', '2015-11-30');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-10-20', '2012-10-28');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-11-04', '2012-11-08');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-11-22', '2012-11-30');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2010-11-22', '2010-11-30');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2020-11-22', '2020-11-30');
我假设我们想要对表S中的每一行以及表T中的每一行进行这些计算。如果不是这种情况,则应该使用一些额外条件来连接表。
在这个例子中,我只使用天精度,而不是分钟,我假设开始和结束日期是包含的,即2000年1月1日和01/01/2000之间的持续时间是一天。将此扩展到精确的精度应该相当简单。
SELECT *
,ISNULL(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo), 0) AS OverlappedDays
FROM
@TableS AS TS
LEFT JOIN @TableT AS TT ON TS.DateFromS <= TT.DateToT AND TS.DateToS >= TT.DateFromT
-- all periods in TS, which overlap with periods in TT
--(StartA <= EndB) and (EndA >= StartB)
CROSS APPLY
(
SELECT CASE WHEN TS.DateFromS > TT.DateFromT THEN TS.DateFromS ELSE TT.DateFromT END AS DateFrom
) AS MaxDateFrom
CROSS APPLY
(
SELECT CASE WHEN TS.DateToS < TT.DateToT THEN TS.DateToS ELSE TT.DateToT END AS DateTo
) AS MinDateTo
LEFT JOIN
中的条件仅留下重叠的间隔。要计算重叠间隔的持续时间,我使用两个CROSS APPLYs
。这是此中间查询的结果集:
ID DateFromS DateToS ID DateFromT DateToT DateFrom DateTo OverlappedDays
1 2012-10-25 2012-11-30 1 2012-10-20 2012-10-28 2012-10-25 2012-10-28 4
1 2012-10-25 2012-11-30 2 2012-11-04 2012-11-08 2012-11-04 2012-11-08 5
1 2012-10-25 2012-11-30 3 2012-11-22 2012-11-30 2012-11-22 2012-11-30 9
2 2015-10-25 2015-11-30 NULL NULL NULL NULL NULL 0
注意,最后一行对应于表S中的间隔与表T中的任何间隔不重叠的情况。
现在我们只需要总结表S中每个原始行的重叠间隔T的持续时间,并从间隔S的持续时间中减去它。
SELECT
TS.ID
,TS.DateFromS
,TS.DateToS
,1+DATEDIFF(day, TS.DateFromS, TS.DateToS) AS DurationS
,ISNULL(SUM(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo)), 0) AS DurationOverlapped
,1+DATEDIFF(day, TS.DateFromS, TS.DateToS)
- ISNULL(SUM(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo)), 0) AS FinalDuration
FROM
@TableS AS TS
LEFT JOIN @TableT AS TT ON TS.DateFromS <= TT.DateToT AND TS.DateToS >= TT.DateFromT
CROSS APPLY
(
SELECT CASE WHEN TS.DateFromS > TT.DateFromT THEN TS.DateFromS ELSE TT.DateFromT END AS DateFrom
) AS MaxDateFrom
CROSS APPLY
(
SELECT CASE WHEN TS.DateToS < TT.DateToT THEN TS.DateToS ELSE TT.DateToT END AS DateTo
) AS MinDateTo
GROUP BY TS.ID, TS.DateFromS, TS.DateToS
这是结果集:
ID DateFromS DateToS DurationS DurationOverlapped FinalDuration
1 2012-10-25 2012-11-30 37 18 19
2 2015-10-25 2015-11-30 37 0 37
您对FinalDuration
值感兴趣,对于您的示例,该值为19,对于此示例,我为第二个间隔添加了37。
您可以向示例数据添加更多间隔以使用查询并查看它们的工作方式。
此解决方案假设表T中的所有间隔彼此不重叠。