按时间查找可用性

时间:2009-07-06 15:33:14

标签: sql-server delphi datetime

我有三张桌子。

  • 表(t),我系统中的资源。 它有最大容量。
  • 预订(b),预订 系统,它来自FromDatimeTime, ToDateTime和nrOfPeople
  • BookedTable(bt),连接 预订桌子和多少个座位 这个预订使用的,a 预订可以有多张桌子。

问题是,如果我有三个预订:

  1. 4人在12:00和 在14:00离开。
  2. 4人在12:00和 在13:00离开。
  3. 4人在13:00和 在14:00离开。
  4. 所有预订都使用同一张桌子,有8个座位。 如果表格“超量预订”,我想查询。

    设置代码

    CREATE TABLE Tables (
            TableNr INT, 
            Seats INT
            )
    GO 
    CREATE TABLE Booking 
        ( 
        BookingNr INT, 
        Time_From DATETIME, 
        Time_TO DATETIME, 
        Guests INT
        )
    GO 
    CREATE TABLE Table_Booking      
    (
     TableBookingId INT ,
     BookingNr INT ,
     TableNr INT ,
     GuestOnTable int 
    )
    GO 
    INSERT INTO [Tables] (  [TableNr],  [Seats]) VALUES ( 1, 8 ) 
    INSERT INTO [Tables] (  [TableNr],  [Seats]) VALUES ( 2, 4 ) 
    INSERT INTO [Tables] (  [TableNr],  [Seats]) VALUES ( 3, 4 ) 
    
    INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 1,/* Time_From - DATETIME */ '2009-7-7 11:00',/* Time_TO - DATETIME */ '2009-7-7 13:00',/* Guests - INT */ 4 ) 
    INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 2,/* Time_From - DATETIME */ '2009-7-7 11:00',/* Time_TO - DATETIME */ '2009-7-7 12:00',/* Guests - INT */ 4 ) 
    INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 3,/* Time_From - DATETIME */ '2009-7-7 12:00',/* Time_TO - DATETIME */ '2009-7-7 13:00',/* Guests - INT */ 4 ) 
    
    
    INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 1,    /* BookingNr - INT */ 1,/* TableNr - INT */ 1, 4 ) 
    INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 2,    /* BookingNr - INT */ 2,/* TableNr - INT */ 1, 4 ) 
    INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 3,    /* BookingNr - INT */ 3,/* TableNr - INT */ 1, 4 ) 
    
    GO 
    

    简单测试查询

    select Booking.BookingNr, [Booking].[Time_From], [Booking].[Time_TO], [Booking].[Guests], [Tables].TableNr  ,  
        CASE WHEN [Tables].[Seats] - 
        (  select sum(tbInner.[GuestOnTable]) from [Table_Booking] as tbInner    
            join [Booking] AS bInner on bInner.BookingNr = tbInner.BookingNr
            where (NOT ( Booking.Time_From>= bInner.[Time_To] OR bInner.[Time_From] >= Booking.Time_To ) )
             ) < 0 THEN 'OverBooked' ELSE 'Ok' END AS TableStatus
            from [Booking] 
            join [Table_Booking] on [Booking].[BookingNr] = [Table_Booking].[BookingNr]
            join [Tables] on [Tables].[TableNr] = [Table_Booking].[TableNr]
    

    给我: Bookingnr 1 =超额预订 预订2和3 =确定。

    如果我删除预订3.我得到了预期的结果。问题是当3个或更多预订在同一张桌子上共享时间时。

    我不想诉诸于在预订期间的所有可能时间做一个循环,并检查它是否超额预订。 查询经常被使用,可能是所有用户每分钟一次,并且一天可能有几百行。 我可以使用SQL或delphi数据集(但我宁愿在SQL中使用它)

    修改1

    它是更大的存储过程的一部分,可以完成所有其他类型的操作,因此它可以是一个函数。

    我希望我不必处理最小间隔。 大多数使用该产品的客户都没有这个问题,因为他们不允许拆分表。而且我不希望查询对他们来说明显变慢。

1 个答案:

答案 0 :(得分:2)

诀窍是扩展你的“预订”表在子查询/ derrived / CTE中,所以每个“间隔”(小时/半小时/分钟/等)是一行,然后你可以SUM - GROUP BY - HAVING SUM()&gt;限制。您可以使用Numbers表来扩展预订表。

使用代码编辑您的问题以构建表格,例如:

DECLARE @t table (col1......   )
INSERT into @t values (......

DECLARE @Booking  table(....
INSERT into @Bookings) values (.....

所以我可以尝试一两个查询,我会尝试为你编写...

修改

要使用下面的查询,您需要创建此表:

CREATE TABLE Numbers
(Number int  NOT NULL,
    CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
DECLARE @x int
SET @x=0
WHILE @x<8000
BEGIN
    SET @x=@x+1
    INSERT INTO Numbers VALUES (@x)
END

这里有一些问题:

--get one row per time "interval" (hour) per booking
SELECT
    b.BookingNr, b.Time_From, b.Time_TO, b.Guests
        ,DATEADD(hh,Number-1,b.Time_From) AS ActualTime
    FROM Booking            b
        INNER JOIN Numbers  n ON DATEADD(hh,Number-1,b.Time_From)<=Time_TO
    ORDER BY 1,5

--get one row per time "interval" (hour), combining each interval
SELECT
    bt.TableNr, SUM(b.Guests) AS TotalGuests
        ,DATEADD(hh,Number-1,b.Time_From) AS ActualTime
    FROM Booking                   b
        INNER JOIN Numbers         n  ON DATEADD(hh,Number-1,b.Time_From)<=Time_TO
        INNER JOIN Table_Booking   bt ON b.BookingNr=bt.BookingNr
    GROUP BY bt.TableNr, DATEADD(hh,Number-1,b.Time_From)
    ORDER BY 3

--get one row per time "interval" (hour), where the seat limit was exceeded
SELECT
    bt.TableNr, SUM(b.Guests) AS TotalGuests
        ,DATEADD(hh,Number-1,b.Time_From) AS ActualTime
        ,t.Seats-SUM(b.Guests) AS SeatsAvailable
    FROM Booking                   b
        INNER JOIN Numbers         n  ON DATEADD(hh,Number-1,b.Time_From)<=Time_TO
        INNER JOIN Table_Booking   bt ON b.BookingNr=bt.BookingNr
        INNER JOIN Tables          t  ON bt.TableNr=t.TableNr
    GROUP BY bt.TableNr,t.Seats, DATEADD(hh,Number-1,b.Time_From)
    HAVING SUM(b.Guests)>t.Seats
    ORDER BY 3

我不确定在超出座位限制时你想怎么处理。如果这些查询不够,请告诉我需要什么...另外,您使用的是哪个版本的SQL Server?