我们首先需要做一个自连接来获取表中所有具有相同FKID的行:
SELECT *
FROM T AS t1
INNER JOIN T AS t2
ON t2.FKID = t1.FKID -- SAME FKID
AND t2.ID <> t1.ID -- Different ID;
条件t2.ID <> t1.ID 将确保您不会将同一行连接到自身,而是在同一个表中查找其他行。这将返回所有行组合,例如
如果您只想要每个元组一次,您可以更改为 t2 > t1.ID,它只会返回
那么对于重叠范围,逻辑的详细版本是:
- 第 2 行的开始日期在第 1 行的开始之后和第 1 行的结束日期之前和结束日期或
- 第 2 行的结束日期在第 1 行的开始之后和第 1 行的结束日期之前
所以用 SQL 术语来说,这就变成了:
CREATE TABLE #T (ID INT, FKID INT, Start DATETIME, [End] DATETIME, TotalTime INT);
INSERT INTO #T(ID, FKID, Start, [End], TotalTime)
VALUES
(208, 40, '2021-07-29 09:30:00', '2021-07-29 09:30:00', 0.9),
(209, 37, '2021-07-29 10:00:00', '2021-07-29 10:00:00', 0.9),
(210, 39, '2021-07-29 10:15:00', '2021-07-29 11:32:00', 77.76),
(211, 40, '2021-07-29 13:00:00', '2021-07-29 14:17:00', 77.76),
(212, 34, '2021-07-29 13:00:00', '2021-07-29 14:28:00', 88.8685714285714),
(213, 39, '2021-07-29 10:30:00', '2021-07-29 11:47:00', 77.76);
SELECT t1.*
FROM #T AS t1
INNER JOIN #T AS t2
ON t2.FKID = t1.FKID -- SAME FKID
AND t2.ID <> t1.ID -- Different ID
WHERE (t2.Start > t1.Start AND t2.Start < t1.[End])
OR (t2.[End] > t1.Start AND t2.[End] < t1.[End]);
不过,我们可以使用 De Morgan's laws 将其简化为:
SELECT t1.*
FROM #T AS t1
INNER JOIN #T AS t2
ON t2.FKID = t1.FKID -- SAME FKID
AND t2.ID <> t1.ID -- Different ID
WHERE t2.Start < t1.[End]
AND t2.[End] > t1.Start;
在这两种情况下,输出都是:
| ID |
FKID |
Start |
End |
TotalTime |
| 210 |
39 |
2021-07-29 10:15:00.000 |
2021-07-29 11:32:00.000 |
77.76 |
| 213 |
39 |
2021-07-29 10:30:00.000 |
2021-07-29 11:47:00.000 |
77.76 |
Example on db<>fiddle
如果您想包含开始日期等于前一行结束日期的行,只需将< 更改为<= 并将> 更改为>=:
SELECT t1.*
FROM #T AS t1
INNER JOIN #T AS t2
ON t2.FKID = t1.FKID -- SAME FKID
AND t2.ID <> t1.ID -- Different ID
WHERE t2.Start <= t1.[End]
AND t2.[End] >= t1.Start;
Example on db<>fiddle 记下 ID 为 214 和 215 的行