1

我有两个 MySQL 表

Payments:
| employeeID | period_begin  | period_end   |

Services:
| serviceID  | date      | employeeID   |

我需要查找由给定员工执行的所有 serviceID,其日期不在付款中描述的任何期间范围之间。因此,例如,如果我有以下关于员工 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 加入Services and Payments 并在那里说明日期条件,但我没有得到正确的答案;我可能应该以不同的条件加入:

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';

不管用。

4

3 回答 3

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)
于 2013-08-05T09:20:58.663 回答
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 的第一个答案基本相同,也许更易于人类阅读。也许还有另一种我们都还没有见过的方式。Sylvain 的子查询确实很不错。

于 2013-08-05T21:07:53.227 回答
0

关于“选择不在任何付款范围内的服务”的主要问题,您可以使用 aLEFT JOIN仅保留没有相应付款范围的行:

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

于 2013-08-05T16:06:18.377 回答