我的问题:
让我们说,我需要在一定时期内(本示例中为10天)找到最好的可能性(一件物品可以提供的最大配额)。 用户想放假5天。
当前查询的示例结果集显示每天的分配量:
+---------+------------+-----------+
| Item Id | Date | Allotment |
+---------+------------+-----------+
| 10 | 20-10-2018 | 100 |
| 10 | 21-10-2018 | 80 |
| 10 | 22-10-2018 | 100 |
| 10 | 23-10-2018 | 100 |
| 10 | 24-10-2018 | 100 |
| 10 | 25-10-2018 | 100 |
| 10 | 26-10-2018 | 100 |
| 10 | 27-10-2018 | 70 |
| 10 | 28-10-2018 | 100 |
| 10 | 29-10-2018 | 100 |
+---------+------------+-----------+
以上示例的结果集是通过以下查询完成的:
foreach($arrivalDates as $key => $date) {
$arrivalDate = $date['from'];
$departureDate = $date['till'];
$allotmentSQLArr[] = "EXISTS (SELECT 1 FROM availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN $arrivalDate AND $departureDate AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration)";
$whereSqlArr[] = "(
EXISTS (SELECT fkItemRoom FROM availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = $arrivalDate AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = $departureDate AND ea.departure_possible = 1)
)";
}
$query = "
SELECT
t.fkItemId,
t.arrival_date,
SUM(t.total_allotment) as total_allotment
FROM (
SELECT
ir.fkItemId,
ir.id,
ea.arrival_date,
(ea.allotment * r.max_occupancy) as total_allotment
FROM
item_room ir
INNER JOIN
room r
ON
r.id = ir.fkRoomId
INNER JOIN
availability as ea
ON
ea.fkItemRoom = ir.id
AND
ea.arrival_date BETWEEN :begin_date AND :end_date
AND
ea.allotment > 0
AND
(".implode(' OR ', $whereSqlArr).")
WHERE
(".implode(' OR ', $allotmentSQLArr).")
) as T
GROUP BY
t.fkItemId, t.arrival_date
";
我正在寻找的解决方案: 现在,我需要知道该项目是否可以为用户提供5天的住宿时间,并且每天至少有80项分配。 在以下期间20-10-2018至24-10-2018,21-10-2018至25-10-2018,22-10-2018至26-10-2018 最大为80 。从23-10-2018到27-10-2018 最大为70 。
在这种情况下,该项目应该可用,因为它可以在至少一个期间内为用户提供分配。
我自己的方法:
SELECT
a.id
FROM
tl_item a
WHERE
EXISTS (
SELECT
1
FROM (
SELECT
t.fkItemId,
t.arrival_date,
SUM(t.total_allotment) as total_allotment
FROM (
SELECT
ir.fkItemId,
ir.id,
ea.arrival_date,
(ea.allotment * r.max_occupancy) as total_allotment
FROM
tl_item_room ir
INNER JOIN
tl_room r
ON
r.id = ir.fkRoomId
INNER JOIN
tl_et_availability as ea
ON
ea.fkItemRoom = ir.id
AND
ea.arrival_date BETWEEN :begin_date AND :end_date
AND
ea.allotment > 0
AND
((
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1539853200 AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540458000 AND ea.departure_possible = 1)
) OR (
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1539939600 AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540544400 AND ea.departure_possible = 1)
) OR (
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540026000 AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540630800 AND ea.departure_possible = 1)
) OR (
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540112400 AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540720800 AND ea.departure_possible = 1)
) OR (
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540198800 AND ea.arrival_possible = 1 AND ((ea.is_maximum IS NULL AND ea.minimum_stay <= :duration) OR (ea.is_maximum = 1 AND ea.minimum_stay = :duration)))
AND
EXISTS (SELECT fkItemRoom FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date = 1540807200 AND ea.departure_possible = 1)
))
AND
(EXISTS (SELECT 1 FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN 1539853200 AND 1540458000 AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration) OR EXISTS (SELECT 1 FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN 1539939600 AND 1540544400 AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration) OR EXISTS (SELECT 1 FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN 1540026000 AND 1540630800 AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration) OR EXISTS (SELECT 1 FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN 1540112400 AND 1540720800 AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration) OR EXISTS (SELECT 1 FROM tl_et_availability ea WHERE fkItemRoom = ir.id AND ea.arrival_date BETWEEN 1540198800 AND 1540807200 AND allotment > 0 HAVING COUNT(ea.fkItemRoom) >= :duration))
) as T
GROUP BY
t.fkItemId,t.arrival_date
) as B
WHERE
((arrival_date BETWEEN 1539853200 AND 1540458000 and total_allotment > :allotment) OR (arrival_date BETWEEN 1539939600 AND 1540544400 and total_allotment > :allotment) OR (arrival_date BETWEEN 1540026000 AND 1540630800 and total_allotment > :allotment) OR (arrival_date BETWEEN 1540112400 AND 1540720800 and total_allotment > :allotment) OR (arrival_date BETWEEN 1540198800 AND 1540807200 and total_allotment > :allotment))
AND
b.fkItemId = a.id
)
我知道,如果只有一条记录符合条件,则以上内容将返回TRUE。我需要实现的是,以下行检查这些日期之间的所有记录是否都分配得更大:
WHERE ((arrival_date BETWEEN 1539853200 AND 1540458000 and total_allotment >= :allotment) OR (arrival_date BETWEEN 1539939600 AND 1540544400 and total_allotment >= :allotment) OR (arrival_date BETWEEN 1540026000 AND 1540630800 and total_allotment >= :allotment) OR (arrival_date BETWEEN 1540112400 AND 1540720800 and total_allotment >= :allotment) OR (arrival_date BETWEEN 1540198800 AND 1540807200 and total_allotment >= :allotment))