SQL для запроса максимального количества доступных элементов за определенный период (система бронирования) - PullRequest
1 голос
/ 08 августа 2010

Для системы бронирования есть стол инвентарь , и у каждого предмета есть количество (например, есть 20 стульев). Теперь пользователь может сделать бронирование на определенный период (например, 5 стульев на два часа "2010-11-23 15:00" - "2010-11-23 17:00"; может быть другое резервирование на несколько дней "2010-11-24 11:00" - "2010-11-26 14:00").

Какой лучший способ проверить, сколько предметов еще доступно за запрошенный период?

Пользователь должен ввести время, когда он хочет сделать заказ (от, до), и он должен увидеть, сколько предметов инвентаря еще доступно за этот период.

table "inventory"
-------------------
inventory_id (int) 
quantity (int)

table "reservation"
-------------------
reservation_id (int)
inventory_id (int)
quantity (int)
from (datetime)
until (datetime)

Резервирование может перекрываться, но на определенный момент времени должны быть зарезервированы только инвентарь. Количество предметов.

Простой пример:

У нас 40 стульев.

Существуют следующие оговорки:

R1 2010-11-23 14:00 - 2010-11-23 15:30 -> 5 chairs reserved
R2 2010-11-23 15:00 - 2010-11-23 16:00 -> 10 chairs reserved
R3 2010-11-23 17:00 - 2010-11-23 17:30 -> 20 chairs reserved

Пользователь делает несколько запросов бронирования (запросов):

Q1 2010-11-23 15:00 - 2010-11-23 17:00 -> 25 chairs are available
Q2 2010-11-23 15:45 - 2010-11-23 17:00 -> 30 chairs are available
Q3 2010-11-23 16:30 - 2010-11-23 18:00 -> 30 chairs are available
Q4 2010-11-23 15:10 - 2010-11-23 15:20 -> 25 chairs are available
Q5 2010-11-23 13:30 - 2010-11-23 17:30 -> 20 chairs are available

Как бы я запросил максимально доступное количество за запрашиваемый период? Или нужен другой дизайн стола? Целевыми системами баз данных являются Oracle и SQL-Server.

Обновление

Я пытался «визуализировать» резервирование R1 и R2 и запросы Q1 - Q5 без изменения исходных примеров. Я добавил Q4 и Q5 в качестве дополнительных примеров. av показывает доступное количество.

       R1  R2  R3  av
13:30              40                  Q5
14:00   5          35                  Q5
14:30   5          35                  Q5
15:00   5  10      25  Q1              Q5
15:10   5  10      25  Q1          Q4  Q5
15:20   5  10      25  Q1              Q5
15:30      10      30  Q1              Q5
15:45      10      30  Q1  Q2          Q5
16:00              40  Q1  Q2          Q5
16:30              40  Q1  Q2  Q3      Q5
17:00          20  20          Q3      Q5
av                     25  30  20  25  20

Ответы [ 2 ]

2 голосов
/ 08 августа 2010

Вы можете попробовать что-то вроде этого (полный рабочий пример)

DECLARE @inventory TABLE(
    inventory_id int, 
    quantity int
)

DECLARE @reservation TABLE(
    reservation_id int,
    inventory_id int,
    quantity int,
    [from] datetime,
    until datetime
)

INSERT INTO @inventory SELECT 1, 40

INSERT INTO @reservation SELECT 1, 1, 5, '2010-11-23 14:00 ', '2010-11-23 15:30'
INSERT INTO @reservation SELECT 1, 1, 10, '2010-11-23 15:00 ', '2010-11-23 16:00'

DECLARE @Start DATETIME,
        @End DATETIME

SELECT  @Start = '2010-11-23 15:00',
        @End = '2010-11-23 17:00'

SELECT  TotalUsed.inventory_id,
        i.quantity - ISNULL(TotalUsed.TotalUsed,0) Available
FROM    @inventory i LEFT JOIN
        (
            SELECT  inventory_id,
                    SUM(quantity) TotalUsed
            FROM    @reservation
            WHERE   [from] BETWEEN @Start AND @End
            OR      until BETWEEN @Start AND @End
            GROUP BY inventory_id
        ) TotalUsed ON  TotalUsed.inventory_id = i.inventory_id


SELECT  @Start = '2010-11-23 15:45',
        @End = '2010-11-23 17:00'

SELECT  TotalUsed.inventory_id,
        i.quantity - ISNULL(TotalUsed.TotalUsed,0) Available
FROM    @inventory i LEFT JOIN
        (
            SELECT  inventory_id,
                    SUM(quantity) TotalUsed
            FROM    @reservation
            WHERE   [from] BETWEEN @Start AND @End
            OR      until BETWEEN @Start AND @End
            GROUP BY inventory_id
        ) TotalUsed ON  TotalUsed.inventory_id = i.inventory_id

Результаты

inventory_id Available
------------ -----------
1            25


inventory_id Available
------------ -----------
1            30
1 голос
/ 09 августа 2010

Использование синтаксиса SQLServer:

SELECT i.inventory_id,
       MAX(i.quantity) - COALESCE(SUM(r.quantity), 0) AS available            
FROM INVENTORY i     
LEFT JOIN RESERVATIONS r 
ON (r.inventory_id = i.inventory_id AND
    r.[from] <= @End AND
    r.until >= @Start)           
GROUP BY i.inventory_id

Я предполагаю, что предоставленные структуры являются упрощенной версией используемых структур - если нет, я рекомендую не использовать ключевые слова, такие как FROM, в качестве имен столбцов.

РЕДАКТИРОВАТЬ: новый запрос, при условии, что заказы выполняются только с точностью до минуты и никогда не превышают одну неделю:

with number_cte(n, n2) as 
 (select n, n+1 n2 from (select 0 n) m union all select n+1 n, n2+1 n2 
  from number_cte where n < datediff("mi",@start,@end))
SELECT i.inventory_id, max(i.quantity) - COALESCE(max(a.alloc), 0) AS available 
from INVENTORY as i  
join
(select n.datesel, r.inventory_id, sum(r.quantity) alloc from
 (select dateadd("mi",n,@Start) datesel from number_cte) as n  
 JOIN RESERVATIONS r 
 ON n.datesel between r.[from] AND r.until 
 GROUP BY n.datesel, r.inventory_id) a 
on i.inventory_id = a.inventory_id
GROUP BY i.inventory_id option (maxrecursion 10080)

На самом деле это было бы проще в Oracle, поскольку вы могли бы использовать соединение по уровням, а не CTE - если у вас будет резервирование дольше, чем одна неделя, вам необходимо соответственно увеличить число maxrecursion.

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