MySQL-联接表必须匹配所有日期的条件

时间:2019-08-07 15:10:37

标签: mysql

我有两个表:resourcesbooking_sums。我想获取在特定日期范围内的资源,每个日期的所有可用时隙都已被预订满。但这被证明是非常困难的。

我有一个booking sums表,该表存储日期和每个日期的三个时隙(event_time)。

booking_sums
--------------
    event_date               (date)
    event_time               (1-3)
    resource id
    sum_booked
    free_seats_left 

我提供了一个event date范围,并获得了满足以下条件的资源:

  • 对于每个event_date,应该在所有三个event_times(1,2和3)中都存在条目,并且每个条目应具有seat_left = 0
  • 日期范围内的所有事件日期必须符合上述条件。

我的问题是,如果只有一个日期符合条件,我仍然会获得资源。

所以,如果我有这些booking_sums:

id  |  event_date  |   event_time  |  resource_id  |  sum_booked  |  free_seats_left  |
id  |  2019-09-18  |        1      |      122      |      250     |        0    |
id  |  2019-09-18  |        2      |      122      |      250     |        0    |
id  |  2019-09-19  |        1      |      122      |      250     |        0    |
id  |  2019-09-19  |        2      |      122      |      250     |        0    |
id  |  2019-09-19  |        3      |      122      |      250     |        0    |

日期2019-09-19符合条件,但日期2019-09-18不匹配。因此,如果日期范围中包含2019-09-18,我们就不应该得到该结果-但我仍然可以得到它。 这是我的查询:

SELECT distinct r.* FROM resources r
INNER JOIN bookings_sums bs1
ON r.id = bs1.resource_id  
WHERE EXISTS(
      SELECT 1 FROM bookings_sums 
      where event_time = 1
      AND resource_id = r.id 
      AND event_date = bs1.event_date 
      AND free_seats_left = 0
    )
AND EXISTS(  SELECT 1 FROM bookings_sums where event_time = 2 AND resource_id = r.id 
       AND event_date = bs1.event_date AND free_seats_left = 0)
AND EXISTS(  SELECT 1 FROM bookings_sums where event_time = 3 AND resource_id = r.id 
       AND event_date = bs1.event_date AND free_seats_left = 0) 

AND bs1.event_date BETWEEN '2019-09-18' AND '2019-09-19'

修改: 这是一个小提琴:sqlfiddle

Edit2 : 从下面建议的有效答案中,我做了一些调整,使其更简单了,似乎可行:

 SELECT r.id, 
        r.title
  FROM resources r
  INNER JOIN bookings_sums bs     
    ON r.id = bs.resource_id 
    AND bs.resource_id = r.id 
    AND bs.event_date 
    BETWEEN '2019-09-19' AND '2019-09-19' AND bs.free_seats_left = 0
  GROUP BY r.id, r.title
  HAVING COUNT(bs.id) = (DATEDIFF('2019-09-19', '2019-09-19') + 1) * 3

(而且我可以使用php代替DATEDIFF并直接输入数字)

1 个答案:

答案 0 :(得分:0)

您应该能够执行此操作而无需子查询。

SELECT r.*
FROM resources r
INNER JOIN bookings_sums bs1
ON r.id = bs1.resource_id
AND bs1.resource_id = r.id
AND bs1.event_date = bs1.event_date
AND bs1.free_seats_left = 0
GROUP BY r......
HAVING SUM(bs.id) = 3
AND bs1.event_date BETWEEN '2019-09-18' AND '2019-09-19'

您将需要在GROUP BY查询中指定资源表上的所有列。

或者只进行3次加入

SELECT r.* 
FROM resources r
INNER JOIN bookings_sums bs1     ON r.id = bs1.resource_id  AND bs1.event_time = 1 AND bs1.resource_id = r.id AND bs1.free_seats_left = 0
INNER JOIN bookings_sums bs2     ON r.id = bs2.resource_id  AND bs2.event_time = 2 AND bs2.resource_id = r.id AND bs2.event_date = bs1.event_date AND bs2.free_seats_left = 0
INNER JOIN bookings_sums bs3     ON r.id = bs3.resource_id  AND bs3.event_time = 3 AND bs3.resource_id = r.id AND bs3.event_date = bs1.event_date AND bs3.free_seats_left = 0
WHERE bs1.event_date BETWEEN '2019-09-18' AND '2019-09-19'

编辑

这可以为您提供所需的东西,但是必须有一种更整齐的方法。

SELECT id,
        title
FROM
(
  SELECT r.id, 
        r.title , 
        sub0.day_cnt
  FROM resources r
  CROSS JOIN
  (
    SELECT DATEDIFF('2019-09-19', '2019-09-18') + 1 AS day_cnt
  ) sub0
  INNER JOIN bookings_sums bs     ON r.id = bs.resource_id AND bs.resource_id = r.id AND bs.event_date BETWEEN '2019-09-18' AND '2019-09-19' AND bs.free_seats_left = 0
  GROUP BY r.id, r.title
  HAVING COUNT(bs.id) = sub0.day_cnt * 3
) sub1;