выбор последовательных чисел с помощью SQL-запроса - PullRequest
4 голосов
/ 25 февраля 2010

Вот план бронирования мест в театре.

Seat No Status
1 Booked
2 Available
3 Available
4 Available
5 Available
6 Available
7 Booked
8 Available
9 Available
10 Available

Если кто-то захочет забронировать 6 билетов, он получит места № 2-6 и место № 8 А если кто-то захочет забронировать только 5 билетов, он получит место № 2 до 6

Как узнать, используя SQL-запрос (или код PHP), если доступных соседних мест больше, чем запрошенных?

Последовательный выбор места - это главная цель, которую мне нужно достичь.

Ответы [ 6 ]

5 голосов
/ 25 февраля 2010

Попробуйте это:

select seat, status
from seats
where seat >= (
   select a.seat
   from seats a
      left join seats b on 
         a.seat < b.seat and
         b.seat < a.seat + 4 and
         b.status = 'Available'
   where a.status = 'Available'
   group by a.seat
   having count(b.seat)+1 = 4
   )
limit 4

Эта опция позволяет выбрать четыре места подряд.Отрегулируйте все значения «4» на желаемое количество мест, чтобы получить то, что вы хотите.

0 голосов
/ 02 декабря 2014
SELECT a.seat_no     SEAT1,
       a.seat_no + 1 SEAT2,
       a.seat_no + 2 SEAT3  
  FROM theater a
 WHERE a.availability = 'Y'
   AND seat_no + 1 = (SELECT b.seat_no 
                        FROM theater b 
                       WHERE b.seat_no = a.seat_no + 1 
                         and b.availability = 'Y')
   AND seat_no + 2 = (SELECT b.seat_no 
                        FROM theater b 
                       WHERE b.seat_no = a.seat_no + 2 
                         and b.availability = 'Y');
0 голосов
/ 25 февраля 2010

Я бы предложил один рекурсивный алгоритм с использованием SQL и PHP. Вам нужно X мест.

  1. Выберите все Доступные места с помощью SQL-запроса, вы получите N доступных мест (Если N

  2. В php проанализируйте результаты и сохраните их, используя в качестве ключа размеры смежных групп мест (может быть несколько групп с одинаковым размером)

    '5' => (2, 3, 4, 5, 6)

    '2' => (8, 9)

  3. Попробуйте найти группу с X местами

  4. Если не найдено, выберите ближайшую группу с размером> X (для X = 4 это группа '5')

  5. Если большие группы не найдены, уберите самую большую из доступных (группа с размером Y), затем повторите шаги 3 - 5 с X = X - Y

0 голосов
/ 25 февраля 2010

лучше представить Забронировано / Доступно в виде двоичных чисел (например, 1 без, 0 забронировано) Если вы это сделаете, вы можете элегантно использовать агрегатные функции:

  select seat as n from seats where
      $num_seats = (select sum(status) from seats
         where seat between n and n + $num_seats - 1)
0 голосов
/ 25 февраля 2010

Один проход. Поставьте свой номер вместо ?. Дает вам номер места в первой последовательности, когда ваше требование было выполнено, или NULL, если последовательность не найдена.

SET @FOUND = 0;
SET @SEAT_MATCHED = NULL;

SELECT
    IF(@FOUND < ?,
        @FOUND := IF(status == 'Booked', 0, @FROM + 1),
        @SEAT_MATCHED := IFNULL(@SEAT_MATCHED, seat_no)
    )
FROM seats
ORDER BY seat_no

SELECT @SEAT_MATCHED;

Подробнее: Функции потока управления , Пользовательские переменные

NB! Этот подход применим только в том случае, если в анализируемом интервале мало записей!

Обновление. Возможно, вы можете сохранить битовую маску забронированных мест в ряду как целое число. Например, для 16-местного ряда номер 36884 (1001000000010100 в двоичном виде) означает 3-е, 5-е, 13-е и 16-е места зарезервированы . Это уменьшит нагрузку на MySQL. И тогда вы можете сделать код следующим образом:

<?php

header('Content-Type: text/plain');

// data you get from DB
$seats = bindec('1001000000010100');
$num_seats = 16;

// calculate consecutive free seats
$seats_info = array();
for ($i = 0; $i < $num_seats; $i++, $seats >>= 1) {
    if ($seats & 1) {
        if (isset($first)) {
            $seats_info[$first] = $i - $first;
            unset($first);
        }
    }
    else {
        if (!isset($first)) {
            $first = $i;
        }
    }
}

// output sequences
var_export($seats_info);

?>

Это выводит:

array (
  0 => 2,
  3 => 1,
  5 => 7,
  13 => 2,
)

0 - это 1-е место.

0 голосов
/ 25 февраля 2010

Редактировать: Так как здесь я неправильно понял вопросы, SQL-оператор, который вернет все первое свободное место и количество смежных мест из первого свободного. На первом месте стоит больше свободных мест.

SELECT count(1) free,(
 CASE status
  WHEN "Booked" THEN
   @prev:=NULL
  ELSE
   @prev:=COALESCE(cast(@prev as unsigned), seat_no)
  END) first
FROM 
 (SELECT @prev:=null) f,
 (SELECT seat_no, status FROM seats ORDER BY seat_no) seats
GROUP BY first
HAVING first>=0
ORDER BY 1 DESC, 2

Так что для вашего примера он вернется:

free | first
-----------
   5    2
   3    8

Если вас интересует только первое последовательное место, которое может соответствовать вашему запросу, и не более того, просто добавьте условие на количество свободных мест, поэтому, если вам нужно 3 места, добавьте free>=3, это сделает:

SELECT count(1) free,(
 CASE status
  WHEN "Booked" THEN
   @prev:=NULL
  ELSE
   @prev:=COALESCE(cast(@prev as unsigned), seat_no)
  END) first
FROM 
 (SELECT @prev:=null) f,
 (SELECT seat_no, status FROM seats ORDER BY seat_no) seats
GROUP BY first
HAVING first>0 AND free>=3
LIMIT 1

это выдаст:

free | first
------------
   5    2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...