2009-07-06 35 views
2

Ich habe drei Tabellen.Suche nach Verfügbarkeit nach Zeit

  • Tabelle (t), eine Ressource in meinem System. Es hat eine maximale Kapazität.
  • Booking (b), eine Reservierung im System, hase es FromDatimeTime, ToDateTime und nrOfPeople
  • BookedTable (bt), verbindet die Buchung mit Tisch und wie viele Sitze , die von dieser Buchung verwendet werden, eine Buchung kann mehr als eine Tabelle haben.

Das Problem ist, dass, wenn ich drei Buchungen:

  1. 4 Personen um 12:00 Uhr und um 14:00 Uhr verlassen comming.
  2. 4 Personen kommen um 12:00 und um 13:00 Uhr verlassen.
  3. 4 Personen kommen um 13:00 und um 14:00 Uhr verlassen.

Alle Buchungen mit der gleichen Tabelle mit 8 Plätzen. Ich möchte sehen, ob der Tisch "überbucht" ist.

Setup-Code

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 

Einfache Testabfrage

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] 

mich gibt: Bookingnr 1 = Buchung overbooked 2 und 3 = Ok.

Wenn ich Buchung entfernen 3. Ich bekomme das erwartete Ergebnis. Das Problem ist, wenn 3 oder mehr Buchungen die gleiche Zeit teilen.

Ich möchte nicht so etwas wie eine Schleife über alle möglichen Zeiten während der Buchung und überprüfen, ob es überbucht ist. Die Abfrage wird häufig verwendet, möglicherweise einmal pro Minute von allen Benutzern, und es kann einige hundert Zeilen für einen Tag geben. kann ich entweder SQL oder delphi Datenmenge verwenden (aber ich würde eher es in SQL tun)

Edit 1

Es ist ein Teil einer größeren gespeicherte Prozedur, die alle Arten von anderen Sachen tun, so Es könnte eine Funktion sein.

Ich würde es vorziehen, dass ich Minintervalle nicht behandeln würde. Die meisten Kunden, die das Produkt verwenden, haben dieses Problem nicht, da sie das Teilen einer Tabelle nicht zulassen. Und ich möchte nicht, dass die Abfrage für sie wesentlich langsamer ist.

+0

In welchem ​​Minintervall sind Sie tätig? Stunde, halbe Stunde oder Minute? –

+0

Kann die Lösung ein auswählbarer gespeicherter Proc sein? Oder muss es eine einzelne SQL-Auswahl sein? –

Antwort

2

Der Trick ist, erweitern Sie Ihre "Buchung" -Tabelle in einer Unterabfrage/abgeleiteten/CTE, so ist das eine Zeile pro "Intervall" (Stunde/halbe Stunde/Minute/etc), dann können Sie SUM - GROUP BY - MIT SUM()> begrenzen. Sie würden eine Tabelle Nummern verwenden, um die Buchungstabelle zu erweitern.

bearbeiten Ihre Frage mit Code, um die Tabellen zu bauen, wie:

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

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

so kann ich eine Abfrage ausprobieren oder zwei, und ich würde versuchen, es für Sie zu schreiben ...

EDIT

um meine Fragen unten zu verwenden, müssen Sie diese Tabelle erstellen:

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 @[email protected]+1 
    INSERT INTO Numbers VALUES (@x) 
END 

sind hier einige Anfragen:

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

Ich bin nicht sicher, wie Sie behandeln möchten, wenn die Sitzgrenze überschritten wird. Wenn diese Abfragen nicht genug sind, lassen Sie mich wissen, was benötigt wird ... Auch, welche Version von SQL Server sind Sie?

+0

Das brachte mich in die richtige Richtung. Und ich löste das Problem schließlich. Der Hauptunterschied, den ich gemacht habe, war, dass ich eine temporäre Tabelle mit möglichen Zeiten anstelle von "DateAdd" in der tatsächlichen Abfrage verwendet habe. Das lag an anderen Designs im System. –