如何在MySQL的某个日期获得'available'个快递员?

How to get 'available' couriers on a certain date in MySQL?

背景

我有一个 table Deliveries:

+---------+-------------+---------------+
| courier | pickup_date | delivery_date |
+---------+-------------+---------------+
| Sebby   | 2015-05-02  | 2015-05-04    |
| Ian     | 2015-05-07  | 2015-05-08    |
| Sebby   | 2015-05-12  | 2015-05-16    |
| Bart    | 2015-05-18  | 2015-05-21    |
| Ian     | 2015-05-27  | 2015-05-29    |
+---------+-------------+---------------+

视觉上,快递员的时间表是这样的:

问题

搜索条件是一个日期范围,我必须 return 在该日期范围内 'available' 哪个快递公司。例如,搜索条件来自 2015-05-16 - 2015-05-17。查看 table 或日历,很容易知道在这些日期只有 Ian 和 Bart 有空。 如何在 MySQL 中执行此操作?

我试过的

我看到这个answer所以我试了一下:

SELECT courier FROM Deliveries
WHERE pickup_date > '2015-05-17'
      OR delivery_date < '2015-05-16'

这给了我伊恩和巴特。但它也包括塞比。这是因为尽管 Sebby 的 2015-05-12 - 2015-05-16 与搜索条件重叠,但 2015-05-02 - 2015-05-04 不重叠,因此它在查询中被 return 编辑。我需要做一些类似限制查询的事情。如果快递员的行程重叠一次,那么查询时不要return。我可以在源代码中执行此操作,但我更喜欢在 MySQL 中执行所有过滤。源代码将是最后的手段。

This 突然出现了我可能已经有了答案的问题,这似乎与我之前的尝试相似。

This question(和答案)也谈到了我之前的尝试。我看到的所有其他内容似乎都以某种方式相关,但没有回答我的问题。

我走在正确的轨道上吗?还是我处理问题的方法不对?

架构

我会提供脚本来创建 table 以节省您的时间:)

CREATE TABLE Deliveries (
    courier varchar(15),
    pickup_date date,
    delivery_date date
);

INSERT INTO Deliveries (courier, pickup_date, delivery_date) VALUES
('Sebby', '2015-05-02', '2015-05-04'),
('Ian', '2015-05-07', '2015-05-08'),
('Sebby', '2015-05-12', '2015-05-16'),
('Bart', '2015-05-18', '2015-05-21'),
('Ian', '2015-05-27', '2015-05-29');

类似的方法可能对您有用。我还建议您使用另一个 table 作为您的快递名称,使事情变得更加优化。

select distinct courier
  from deliveries d
    where not exists (
      select 1 from deliveries d2
        where d.courier = d2.courier
          and (('2015-05-16' between pickup_date and delivery_date)
                  or ('2015-05-17' between pickup_date and delivery_date)
                  or (pickup_date between '2015-05-16' and '2015-05-17')
                  or (delivery_date between '2015-05-16' and '2015-05-17'))
    )

demo here

通过使用 where not exists,这应该排除以下任何快递员:

  1. 有一个跨越搜索期开始的交付
  2. 有一个跨越搜索期结束的交付
  3. 在您的搜索期限内有取件日期的送货
  4. 有交货日期在您的搜索期限内

我认为这涵盖了所有基础 -- 只有最后两个中的一个是绝对必要的,它涵盖了现有交付完全在搜索期内的情况

您的查询在某种程度上与字符串到日期时间的转换有关 --

因为您的数据库 table 字段似乎没有以日期时间或日期格式存储内容 --

所以你的查询应该是这样的--

SELECT courier
  FROM Deliveries
 WHERE STR_TO_DATE(pickup_date, '%m/%d/%Y') > '2015-05-17' OR STR_TO_DATE(pickup_date, '%m/%d/%Y') < '2015-05-16' ;

你想知道快递员在忙的地方有没有一行,过滤掉那些快递员。这是为了确定您的日期范围是否与取货日期和交货日期的某些范围重叠:

select distinct d1.courier from Delivers d1
where not exists(select * from Delivers d2
                 where d1.courier = d2.courier and
                 d2.pickDate <= '2015-05-17' and d2.deliveryDate >= '2015-05-16')

2个区间有9种可能的情况。可以只评估不同情况下的谓词:

http://yetanothermathprogrammingconsultant.blogspot.com/2014/09/when-do-two-intervals-overlap.html

以下查询将为您执行此操作,请查看 fiddle

SELECT DISTINCT courier FROM Deliveries WHERE courier NOT IN (
    SELECT courier 
    FROM Deliveries
    WHERE (('2015-05-17' between pickup_date AND delivery_date)
       OR ('2015-05-16' between pickup_date AND delivery_date))
);

编辑:

SELECT DISTINCT courier FROM Deliveries WHERE courier NOT IN (
  SELECT courier 
  FROM Deliveries
  WHERE (('2015-05-17' between pickup_date AND delivery_date)
      OR ('2015-05-14' between pickup_date AND delivery_date))
      OR ((pickup_date between '2015-05-14' AND '2015-05-17')
      OR ( delivery_date between '2015-05-14' AND '2015-05-17'))
);