如何解决正确计算两个日期范围之间的时间
我正在使用Datetime列,由于时间重叠,我无法计算时间。
这是我的示例数据
Declare @T table (ID Int,InTime Datetime,OutTime Datetime)
Insert into @T values (1,'2020-08-23 09:26:07.000','2020-08-23 09:57:55.000')
Insert into @T values (1,'2020-08-23 14:09:08.000','2020-08-26 08:13:45.000')
Insert into @T values (1,'2020-08-24 11:14:37.000','2020-08-24 18:07:25.000')
Insert into @T values (1,'2020-08-25 09:19:38.000','2020-08-25 19:19:29.000')
Insert into @T values (1,'2020-08-26 08:13:50.000','2020-08-28 08:39:23.000')
Insert into @T values (1,'2020-08-27 08:42:16.000','2020-08-27 11:38:06.000')
Insert into @T values (1,'2020-08-27 09:51:14.000','2020-08-28 18:23:06.000')
Insert into @T values (1,'2020-08-29 09:51:14.000','2020-08-30 18:23:06.000')
我的预期输出:
+----+-------------------------+--------------------------+
| ID | InTime | OutTime |
+----+-------------------------+--------------------------+
| 1 | 2020-08-23 09:26:07.000 | 2020-08-23 09:57:55.000 |
| 1 | 2020-08-23 14:09:08.000 | 2020-08-26 08:13:45.000 |
| 1 | 2020-08-26 08:13:50.000 | 2020-08-28 08:39:23.000 |
| 1 | 2020-08-29 09:51:14.000 | 2020-08-30 18:23:06.000 |
+----+-------------------------+--------------------------+
如果您在表格中看到第二个条目,其中我的Intime是2020-08-23 14:09:08.000而outTime是2020-08-26 08:13:45.000。因此,如果表中的任何条目在23到26之间,我们都应跳过该条目。因此在外表中,我们需要跳过第24和25个条目。
有人可以帮助我进行此查询吗?任何帮助将不胜感激
我尝试了此链接,但无法理解逻辑 Link
解决方法
这是“聚合间隔”的经典情况。 Snodgrass给出了一个经典的查询:
WITH
T0 AS
(SELECT PRE.id,PRE.intime AS D1,PRE.outtime AS F1,DER.intime AS D2,DER.outtime AS F2
FROM @T PRE
INNER JOIN @T DER
ON PRE.intime <= DER.outtime
AND PRE.id = DER.id)
SELECT DISTINCT id,D1 AS intime,F2 AS outtime
FROM T0 AS I
WHERE NOT EXISTS (SELECT *
FROM @T SI1
WHERE (SI1.intime < I.D1
AND I.D1 <= SI1.outtime
AND I.id = SI1.id )
OR (SI1.intime <= I.F2
AND I.F2 < SI1.outtime
AND I.id = SI1.id))
AND NOT EXISTS (SELECT *
FROM @T SI2
WHERE D1 < SI2.intime
AND SI2.intime <= F2
AND I.id = SI2.id
AND NOT EXISTS (SELECT *
FROM @T SI3
WHERE SI3.intime < SI2.intime
AND SI2.intime <= SI3.outtime
AND SI2.id = SI3.id ));
Chris Date给出另一个版本:
WITH T
AS (SELECT F.intime,L.outtime,F.id
FROM @T AS F
JOIN @T AS L
ON F.outtime <= L.outtime
AND F.id = L.id
INNER JOIN @T AS E
ON F.id = E.id
GROUP BY F.intime,F.id
HAVING COUNT(CASE
WHEN (E.intime < F.intime AND F.intime <= E.outtime)
OR (E.intime <= L.outtime AND L.outtime < E.outtime)
THEN 1
END) = 0)
SELECT id,intime,MIN(outtime) AS outtime
FROM T
GROUP BY id,intime;
最后我写了一篇:
WITH
T0 AS -- suprime les périodes incluses
(SELECT DISTINCT Tout.id,Tout.intime,Tout.outtime
FROM @T AS Tout
WHERE NOT EXISTS(SELECT *
FROM @T AS Tin
WHERE Tout.intime >= Tin.intime
AND Tout.outtime < Tin.outtime
AND Tout.id = Tin.id)),T1 AS -- ancres : périodes de tête...
(SELECT Ta.*,1 AS ITERATION
FROM T0 AS Ta
WHERE NOT EXISTS(SELECT *
FROM T0 AS Tb
WHERE Tb.outtime >= Ta.intime
AND Tb.outtime < Ta.outtime
AND Tb.id = Ta.id)
UNION ALL -- itération sur période dont le debut est inclus dans les bornes de la période ancre
SELECT T1.id,T1.intime,T0.outtime,T1.ITERATION + 1
FROM T1
INNER JOIN T0
ON T1.intime < T0.intime
AND T1.outtime >= T0.intime
AND T1.outtime < T0.outtime
AND T1.id = T0.id),T2 AS
(SELECT *,ROW_NUMBER() OVER(PARTITION BY id,intime ORDER BY DATEDIFF(s,outtime) DESC) AS N1,outtime ORDER BY DATEDIFF(s,outtime) DESC) AS N2
FROM T1)
SELECT id,outtime
FROM T2
WHERE N1 = 1 AND N2 = 1;
这是递归查询
Itzik Ben Gan已经做了一些更复杂,性能更高的查询...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。