所以你必须找到所有的 [fired,hired] 间隔。
我这里的方法是首先选择给定范围内的所有“触发日期”(在所需间隔的开始和结束时合成假触发日期)。然后对雇佣日期做同样的事情——最后成对匹配。
作为一张价值 1000 字的图片,这里以图形方式展示了查询的工作原理:
这导致了一个相当复杂的查询(而且效率低下——可能需要几个临时表 + 文件排序):
SELECT * FROM
( -- Keep numbered list of "fired" date
SELECT (@i := @i+1) as n, F.* FROM (
SELECT @start AS fired
UNION SELECT fired FROM hirefire
WHERE fired > @start and hired < @end
UNION SELECT @end
) AS F
JOIN (SELECT @i := 0) AS init -- initialize @i
ORDER BY F.fired ASC
) AS F
JOIN
( -- Keep numbered list of "hired" date
SELECT (@j := @j+1) as n, H.* FROM (
SELECT @start AS hired
UNION SELECT hired FROM hirefire
WHERE fired > @start and hired < @end
UNION SELECT @end
) AS H
JOIN (SELECT @j := 0) AS init -- initialize @j
ORDER BY H.hired ASC
) AS H
ON( F.n+1 = H.n )
WHERE H.hired <> F.fired;
有关实时示例,请参阅http://sqlfiddle.com/#!2/a841d0/39
举个例子:
create table hirefire(pk serial, hired int, fired int);
insert into hirefire(hired, fired) values
(1,3), (5,10), (12,14), (16,25);
SET @start = 4;
SET @end = 30;
会产生
+----+--------+-------+
| N | FIRED | HIRED |
+----+--------+-------+
| 1 | 4 | 5 |
| 2 | 10 | 12 |
| 3 | 14 | 16 |
| 4 | 25 | 30 |
+----+--------+-------+
再解释几句:
- 如您所见,我使用用户定义的变量来编号行(需要轻松地成对匹配)
- 我使用这个
JOIN (SELECT @j := 0)
技巧来初始化这些变量,而不需要单独的SET ...
语句
- 我在这里通过使用整数范围来简化问题,以便通过减少“噪音”来保持答案易于理解。你将不得不适应它
DATETIME
。
- 我使用“纯 SQL”来找到最初需要的答案,但由于存在一些基于“行号”的匹配,因此在应用程序级别解决这部分问题可能是最有效的;)
这里仅供参考我的原始答案。它通过发出 [hired,fired] 间隔来生成正确查询的补充。
假设您有一个间隔 [@start @end)
SELECT DISTINCT GREATEST(@start, hired), LEAST(@end, fired)
FROM hirefire
WHERE @start < fired AND @end >= hired;
我不太确定不平等/严格不平等的事情,但这就是精神。
有关示例,请参见http://sqlfiddle.com/#!2/a841d0/7 。DATETIME
它使用纯整数来定义范围,但我认为您无需付出太多努力就可以适应它。