我有两个MySQL表
Payments:
| employeeID | period_begin | period_end |
和
Services:
| serviceID | date | employeeID |
我需要查找给定员工执行的所有serviceID,其日期不在Payments中描述的任何期间范围之间。因此,例如,如果我在员工10000的付款和服务上有以下记录:
Payments:
| employeeID | period_begin | period_end |
...
| 10000 | 2013-05-01 | 2013-05-16 |
| 10000 | 2013-05-17 | 2013-06-02 |
| 10000 | 2013-07-01 | 2013-07-16 |
| 10000 | 2013-07-17 | 2013-08-02 |
...
Services:
| serviceID | date | employeeID |
...
| 2001 | 2013-01-01 | 10000 |
| 2002 | 2013-05-15 | 10000 |
| 2003 | 2013-06-01 | 10000 |
| 2004 | 2013-07-10 | 10000 |
| 2005 | 2013-08-01 | 10000 |
...
输出应为
2001, 2003年, 2005
因为服务2002,2004的日期位于付款表中的一个时间间隔内。
有什么想法吗?我无法检查服务的日期是否未计入Payments表中记录的其中一个时间间隔。我目前正在加入employeeID上的服务和付款,并说明那里的日期条件,但我没有得到正确答案;我应该加入一个不同的条件:
select distinct serviceID from Services as X left join Payments as Y on
(X.employeeID=Y.employeeID AND (X.date < Y.period_begin OR X.date > Y.period_end))
where X.employeeID='10000';
无效。
答案 0 :(得分:2)
... AND X.date < Y.period_begin and X.date > Y.period_end
显然是不可能的(日期不能在开始日期之前和结束日期之后......)
你可能想写:
... AND (X.date < Y.period_begin or X.date > Y.period_end)
请将“OR”表达式括在括号中。我认为这对于运算符优先级很重要,并且它提高了可读性。
编辑:正如@BigToach在评论中所建议的那样,您可以使用NOT BETWEEN ... AND ...
(如果AND
字在该上下文中不太混淆):
... AND (X.date NOT BETWEEN Y.period_begin AND Y.period_end)
答案 1 :(得分:0)
关于“选择不在任何付款范围内的服务”的主要问题,您可以使用LEFT JOIN
仅保留没有相应付款范围的行:< / p>
SELECT Services.* FROM Services
LEFT JOIN
(SELECT serviceID,period_begin FROM Services
JOIN Payments
USING (employeeID)
WHERE employeeID = @EID
AND the_date BETWEEN Payments.period_begin AND Payments.period_end
) AS X
USING (serviceID)
WHERE employeeID = @EID
AND period_begin is NULL;
或者,使用子查询 - 稍微更具可读性,但通常效率较低:
SELECT Services.* FROM Services
WHERE employeeID = @EID
AND serviceID NOT IN (SELECT serviceID FROM Services JOIN Payments
USING (employeeID)
WHERE employeeID = @EID
AND the_date BETWEEN Payments.period_begin AND Payments.period_end);
答案 2 :(得分:0)
正如BigToach和Sylvain Leroux所指出的,显然有一个逻辑错字使AND与OR混淆。但是,一旦修复,该查询仍然没有给出正确的答案。我设法得到了正确的解决方案,首先找到包含在某个时间间隔内的所有serviceID,然后从所有serviceID列表中排除这些:
select distinct serviceID from Services as X left join Payments as Y on
(X.employeeID=Y.employeeID) where X.employeeID='10000'
and X.serviceID not in (
select serviceID from Services as Z join Payments as W on
(Z.employeeID=W.employeeID and
(Z.date between W.period_begin and W.period_end))
where Z.employeeID='10000'
);
然而,这个查询不是很漂亮,因为我真的在做两个查询,但它与Sylvain Leroux的第一个答案基本相同,可能更具人性化。也许还有另一种方式我们都还没见过。西尔万的子查询确实非常好。