Looking for accessibility with MySQL (and PHP)?

I have two MySQL tables (MyIsAm), which are units and orders:

  • LettingUnits ( ID, Nameetc.)
  • LettingUnitBookings ( ID, F_LU_ID, Start, End)

Where F_LU_IDis the foreign key for the device.

What is the best way to search for units available over a period of time? The search goes through the beginning, end and duration.

  • Start = The earliest start of the reservation.
  • End = Last end of the reservation.
  • Duration = Duration of the reservation.

I would be interested to know if this is possible to do in MySQL, but if not, then the best way to do it in PHP.

Example

In response to the answers below, I feel like an example will help explain the problem.

A LettingUnit:

  • (123, "Foo Cottage" )

LettingUnitBookings:

  • (400, 123, 01/01/09, 05/01/09) - 5 .
  • (401, 123, 10/01/09, 20/01/09) - 10 .
  • (402, 123, 25/01/09, 30/01/09) - 5 .

:

  • = 01/01/09
  • = 01/02/09
  • = 5 ()

, . 5 .

10, , 10 .

+3
2

, :

SELECT t.*, DATEDIFF(t.LatestAvailable, t.EarliestAvailable) AS LengthAvailable
FROM 
   (SELECT u.*,
      COALESCE(b1.End, @StartOfWindow) AS EarliestAvailable,
      COALESCE(b2.Start, @EndOfWindow) AS LatestAvailable
    FROM LettingUnits u
    LEFT OUTER JOIN LettingUnitBookings b1
      ON (u.ID = b1.F_LU_ID AND b1.End BETWEEN @StartOfWindow AND @EndOfWindow)
    LEFT OUTER JOIN LettingUnitBookings b2
      ON (u.ID = b2.F_LU_ID AND b2.Start BETWEEN @StartOfWindow AND @EndOfWindow
          AND b2.Start >= b1.End) -- edit: new term
    ) AS t
LEFT OUTER JOIN LettingUnitBookings x
  ON (t.ID = x.F_LU_ID AND x.Start < t.LatestAvailable AND x.End > t.EarliestAvailable)
WHERE x.ID IS NULL AND DATEDIFF(t.LatestAvailable, t.EarliestAvailable) >= @WindowSize;

:

+-----+-------------+-------------------+-----------------+-----------------+
| ID  | Name        | EarliestAvailable | LatestAvailable | LengthAvailable |
+-----+-------------+-------------------+-----------------+-----------------+
| 123 | Foo Cottage | 2009-01-05        | 2009-01-10      |               5 |
| 123 | Foo Cottage | 2009-01-20        | 2009-01-25      |               5 |
| 456 | Bar Cottage | 2009-01-20        | 2009-01-31      |              11 |
+-----+-------------+-------------------+-----------------+-----------------+

EXPLAIN , :

+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | Extra                   |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL  |    9 | Using where             |
|  1 | PRIMARY     | x          | ref    | F_LU_ID       | F_LU_ID | 8       | t.ID  |    2 | Using where; Not exists |
|  2 | DERIVED     | u          | system | NULL          | NULL    | NULL    | NULL  |    1 |                         |
|  2 | DERIVED     | b1         | ref    | F_LU_ID       | F_LU_ID | 8       | const |    0 |                         |
|  2 | DERIVED     | b2         | ref    | F_LU_ID       | F_LU_ID | 8       | const |    0 |                         |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------------------+

EXPLAIN @martin clayton:

+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
| id | select_type  | table               | type   | possible_keys | key     | key_len | ref  | rows | Extra                           |
+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+
|  1 | PRIMARY      | lu                  | system | PRIMARY,ID    | NULL    | NULL    | NULL |    1 |                                 |
|  1 | PRIMARY      | <derived2>          | ALL    | NULL          | NULL    | NULL    | NULL |    4 | Using where                     |
|  2 | DERIVED      | <derived3>          | ALL    | NULL          | NULL    | NULL    | NULL |    4 | Using temporary; Using filesort |
|  2 | DERIVED      | <derived5>          | ALL    | NULL          | NULL    | NULL    | NULL |    4 | Using where; Using join buffer  |
|  5 | DERIVED      | LettingUnitBookings | ALL    | NULL          | NULL    | NULL    | NULL |    3 |                                 |
|  6 | UNION        | LettingUnitBookings | index  | NULL          | F_LU_ID | 8       | NULL |    3 | Using index                     |
| NULL | UNION RESULT | <union5,6>          | ALL    | NULL          | NULL    | NULL    | NULL | NULL |                                 |
|  3 | DERIVED      | LettingUnitBookings | ALL    | NULL          | NULL    | NULL    | NULL |    3 |                                 |
|  4 | UNION        | LettingUnitBookings | index  | NULL          | F_LU_ID | 8       | NULL |    3 | Using index                     |
| NULL | UNION RESULT | <union3,4>          | ALL    | NULL          | NULL    | NULL    | NULL | NULL |                                 |
+----+--------------+---------------------+--------+---------------+---------+---------+------+------+---------------------------------+

, , Using filesort Using temporary, . GROUP BY ​​, , MySQL.

+2

.

  • LettingUnitBookings
  • F_LU_ID
  • -
  • , , "" ,
  • LettingUnits WHERE (, , )

BookingUnits, .

:

SELECT @StartOfWindow := '2009-01-01',
       @EndOfWindow   := '2009-02-01',
       @WindowSize    := 5
;

SELECT
    lu.Name,
    Slots.*
FROM (
    SELECT
        lub1.F_LU_ID,
        DATE_ADD( MAX( lub2.date_time ), INTERVAL 1 DAY )     AS StartOfSlot,
        DATE_SUB( lub1.date_time, INTERVAL 1 DAY )            AS EndOfSlot,
        DATEDIFF( lub1.date_time, MAX( lub2.date_time ) ) - 1 AS AvailableDays
    FROM
    ( SELECT F_LU_ID, Start AS date_time FROM LettingUnitBookings
      UNION
      SELECT F_LU_ID, CAST( '9999-12-31' AS DATE ) FROM LettingUnitBookings
    ) AS lub1,
    ( SELECT F_LU_ID, End   AS date_time FROM LettingUnitBookings
      UNION
      SELECT F_LU_ID, CAST( '1000-01-01' AS DATE ) FROM LettingUnitBookings
    ) AS lub2
    WHERE
        lub2.date_time <= lub1.date_time
    AND lub2.F_LU_ID = lub1.F_LU_ID
    GROUP BY
        lub1.F_LU_ID,
        lub1.date_time
    ) Slots
JOIN LettingUnits lu
ON   lu.ID = Slots.F_LU_ID
WHERE
    Slots.AvailableDays >= @WindowSize
AND (
   (     DATEDIFF( Slots.EndOfSlot, @EndOfWindow )     >= @WindowSize
     AND DATEDIFF( @StartOfWindow, Slots.StartOfSlot ) >= @WindowSize
   )
   OR
   (     DATEDIFF( @EndOfWindow, Slots.StartOfSlot ) >= @WindowSize
     AND DATEDIFF( Slots.EndOfSlot, @StartOfWindow ) >= @WindowSize
   )
)

Name        F_LU_ID StartOfSlot EndOfSlot  AvailableDays
Foo Cottage 123     2009-01-06  2009-01-09 5
Foo Cottage 123     2009-01-21  2009-01-24 5

, .

, , , ...

SELECT
    lu.Name,
    Slots.*
FROM (
    SELECT
        lub1.F_LU_ID,
        MAX( lub2.date_time ) AS StartOfSlot,
        lub1.date_time        AS EndOfSlot,
        DATEDIFF( lub1.date_time, MAX( lub2.date_time )) AS AvailableDays
    FROM
    ( SELECT F_LU_ID, Start AS date_time FROM LettingUnitBookings
      UNION
      SELECT F_LU_ID, CAST( '9999-12-31' AS DATE ) FROM LettingUnitBookings
    ) AS lub1,
    ( SELECT F_LU_ID, End   AS date_time FROM LettingUnitBookings
      UNION
      SELECT F_LU_ID, CAST( '1000-01-01' AS DATE ) FROM LettingUnitBookings
    ) AS lub2
    WHERE
        lub2.date_time <= lub1.date_time
    AND lub2.F_LU_ID = lub1.F_LU_ID
    GROUP BY
        lub1.F_LU_ID,
        lub1.date_time
    ) Slots
JOIN LettingUnits lu
ON   lu.ID = Slots.F_LU_ID
WHERE
    Slots.AvailableDays >= @WindowSize
AND
   (     DATEDIFF( Slots.EndOfSlot, @EndOfWindow )     >= @WindowSize
     AND DATEDIFF( @StartOfWindow, Slots.StartOfSlot ) >= @WindowSize
   )
   OR
   (     DATEDIFF( @EndOfWindow, Slots.StartOfSlot ) >= @WindowSize
     AND DATEDIFF( Slots.EndOfSlot, @StartOfWindow ) >= @WindowSize
   )
+1

Source: https://habr.com/ru/post/1722107/


All Articles