用于查询特定期间(预订系统)的最大可用项目数的SQL

用于查询特定期间(预订系统)的最大可用项目数的SQL,sql,sql-server,oracle,Sql,Sql Server,Oracle,对于预订系统,有一个库存表,每个项目都有一个数量,例如有20把椅子。现在,用户可以预订一段特定的时间,例如2010-11-23 15:00-2010-11-23 17:00两小时5张椅子;另一个预订可能是几天2010-11-24 11:00-2010-11-26 14:00 最好的检查方法是什么,在请求的时间段内还有多少物品可用 用户应输入他希望从、到进行预订的时间,并应查看此期间还有多少库存项目可用 table "inventory" ------------------- inventory

对于预订系统,有一个库存表,每个项目都有一个数量,例如有20把椅子。现在,用户可以预订一段特定的时间,例如2010-11-23 15:00-2010-11-23 17:00两小时5张椅子;另一个预订可能是几天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)
保留可以重叠,但对于某个时间点,只能保留inventory.quantity项

简单的例子:

我们有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

你可以试试这个完整的工作示例

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
结果


使用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数。

不包括预订在@Start之前和@end之后有[from]的情况-例如,如果[from]是“2010-11-22 09:00”,直到是“2010-11-24 18:00”。我已经更新了示例。我认为第四季度15:10-15:20的结果是错误的。它返回40。是的,它只是简化了。from不是真正的列名。这是个坏名声。我在第一次回答后就注意到了。我认为你的查询得到了正确的结果。我怀疑,这不可能这么容易。我已经更新了问题并添加了预订R3。如果有一个查询Q5 13:30-17:30,此查询将对所有保留进行求和,留下5个可用的保留,但结果应为20,因为这是在同一时间段所需的最大数目。@soundlink-尝试新查询。
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)