MySQL-每个周期的最小值的最大值

时间:2018-10-22 12:11:48

标签: php mysql sqlperformance

我的问题:

让我们说,我需要在一定时期内(本示例中为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))

0 个答案:

没有答案