选择日期不在间隔中的位置

时间:2013-08-05 09:18:15

标签: mysql

我有两个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';

无效。

3 个答案:

答案 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);

请参阅http://sqlfiddle.com/#!2/a3557/11

答案 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的第一个答案基本相同,可能更具人性化。也许还有另一种方式我们都还没见过。西尔万的子查询确实非常好。