简体   繁体   English

选择不在间隔中的日期

[英]Select where date not in interval

I have two MySQL tables 我有两个MySQL表

Payments:
| employeeID | period_begin  | period_end   |

and

Services:
| serviceID  | date      | employeeID   |

I need to find all serviceIDs performed by a given employee whose date is not between any of the period ranges described in Payments. 我需要查找给定员工的日期不在“付款”中描述的任何时间范围之间的所有serviceID。 So, for example if I have the following records on Payments and Services for employee 10000: 因此,例如,如果我在“员工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     |
...

The output should be 输出应为

2001, 2003, 2005 2001、2003、2005

because the dates for services 2002, 2004 are in one of the intervals in the Payments table. 因为服务2002、2004的日期在“付款”表中的时间间隔之一中。

Any ideas? 有任何想法吗? I'm having trouble checking that a service's date is not accounted for one of the intervals recorded on the Payments table. 我无法检查服务的日期是否未计入“付款”表中记录的间隔之一。 I'm currently joining Services and Payments on employeeID and stating the date condition there, but I'm not getting the right answer; 我目前正在加入employeeID上的“服务和付款”并在其中说明日期条件,但是我没有得到正确的答案; I should probably be joining on a different condition: 我可能应该以其他条件加入:

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

is not working. 不管用。

... AND X.date < Y.period_begin and X.date > Y.period_end

Is obviously impossible (the date cannot be before the start date and after the end date...) 显然是不可能的(日期不能在开始日期之前结束日期之后...)

You probably want to write: 您可能想写:

... AND (X.date < Y.period_begin or X.date > Y.period_end)

Please wrap the "OR" expression is parenthesis. 请用括号将“或”表示形式换行。 I think this is important regarding operator precedence and it improves readability. 我认为这对于运算符优先级很重要,并且可以提高可读性。

EDIT: As suggested by @BigToach in a comment, you could use NOT BETWEEN ... AND ... (if the AND word is not too confusing in that context): 编辑:如@BigToach在评论中所建议,您可以使用NOT BETWEEN ... AND ... (如果AND字在该上下文中不太混乱):

... AND (X.date NOT BETWEEN Y.period_begin AND Y.period_end)

Concerning the main problem which is "select the services not in any payment range" you could use a LEFT JOIN to keep only the row that does not have a corresponding payment range: 关于“选择不在任何付款范围内的服务”这一主要问题,您可以使用LEFT 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;

Or, use a subquery -- somewhat more readable, but usually less efficient: 或者,使用子查询-更具可读性,但通常效率较低:

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

See http://sqlfiddle.com/#!2/a3557/11 参见http://sqlfiddle.com/#!2/a3557/11

As indicated by BigToach and Sylvain Leroux, there was clearly a logic-typo confusing an AND with an OR. 正如BigToach和Sylvain Leroux所指出的那样,显然有一个逻辑上的错字将AND与OR混淆。 However, once fixed, that query still doesn't give the right answer. 但是,一旦修复,该查询仍无法给出正确的答案。 I managed to get the right solution by first finding all serviceIDs for contained in some interval, and then excluding those from the list of all serviceIDs: 我设法找到了正确的解决方案,方法是先找到某个间隔中包含的所有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'
    );

This query, however, is not very pretty as I'm really doing two queries, but it's basically the same thing than Sylvain Leroux first answer, perhaps a bit more human-readable. 但是,此查询不是很漂亮,因为我实际上是在进行两个查询,但它与Sylvain Leroux的第一个答案基本上是同一回事,也许更易于理解。 Maybe there is yet another way we all haven't seen yet. 也许还有另一种我们还没有见过的方式。 Sylvain's subquery is indeed very nice. Sylvain的子查询确实非常好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM