| 

.NET C# Java Javascript Exception

2
Hallo,

also Problem ist folgendes:
Wir haben eine SQL-Datenbank "Hotel" mit folgenden Tabellen und Feldern:
1. Reservierungen:
- Reservierungs-ID (Primärschlüssel, auto-inc)
- Zimmernummer
- Kundennummer
- Anreisedatum
- Abreisedatum
- Status ("0"=Reservierung in der Zukunft, "1"=Gast ist eingecheckt, "2"=Reservierung in der Vergangenheit)

2. Zimmer:
- Zimmernummer (Primärschlüssel)
- Kategorie

Die Tabellen "Kunden" (mit allen Kundendetails) und "Zimmerpreis" (Kategorie und Preis) sind auch vorhanden, aber für die Frage nicht relevant denk ich mir mal.

So, nun zum eigentlichen Problem:
Ich will eine SELECT-Abfrage finden, die mir freie Zimmer (d.h. keine Reservierung) innerhalb eines vorgegebenen Zeitraums (Anreise- bzw. Abreisedatum) liefert und komme nicht weiter!
Gibts da irgendein SELECT-Statement mit dem ich das schaffen könnte oder muss ich die Datenbank irgendwie verändern um das möglich zu machen?

Danke schonmal im Voraus!
18.09.2009
honigbaron 43 3
5 Antworten
5
In der Hoffnung, du hast die Daten (pl. von Datum) auch als date abgespeichert, würde ich es wie folgt machen:

abfrage 1:
select zimmernummer from reservierungen 
where anreisedatum<=Abreise
and abreisedatum>=Anreise
and status != "2"
group by zimmernummer;


abfrage 2:
select zimmernummer from zimmer 
where zimmernummer not in (ergebnis aus abfrage 1);



In Abfrage 1 kannst du das Istgleich in <= und >= auch weglassen, wenn am selben Tag Reservierungen Enden und Starten dürfen.
18.09.2009
cyper 116 3
1
Auch wenn der Fragesteller bereits eine Antwort akzeptiert hat, möchte ich das Thema JOIN nochmal aufgreifen.
Um es klarzustellen: Mit einem einfachen JOIN (egal ob INNER oder OUTER) läßt sich das Problem der freien Zimmer nicht lösen. Ein JOIN arbeitet Datensatzweise und das genügt für die Ermittlung der freien Zimmer NICHT.
Mit einem JOIN kann man dagegen die belegten Zimmer abfragen:
select distinct z.zimmernummer
from zimmer z
inner join reservierungen r
on r.zimmernummer = z.zimmernummer
and r.abreisedatum >= :anreise
and r.anreisedatum <= :abreise

Hierfür genügt ein INNER JOIN, es ist kein LEFT JOIN notwendig.

Um die freien Zimmer in einer Abfrage zu erhalten, kann man die beiden Abfragen von cyper in einem Subselect kombinieren.
select zimmernummer 
from zimmer
where zimmernummer not in (
select zimmernummer
from reservierungen
where anreisedatum <= :abreise
and abreisedatum >= :anreise
)

Möchte man die Aufgabe ohne Subselect mit einem JOIN lösen, so geht dies nur mit einer zusätzlichen Bedingung. Die Menge der freien Zimmer ist die OUTER JOIN Menge der belegten Zimmer ohne Reservierungen.
select z.zimmernummer
from zimmer z
left join reservierungen r
on r.zimmernummer = z.zimmernummer
and r.abreisedatum >= :anreise
and r.anreisedatum <= :abreise
group by z.zimmernummer
having count(r.zimmernummer) = 0

Wichtig ist hier (damit der OUTER JOIN funktioniert) die Zeitraumabfrage in der JOIN-Bedingung und nicht in der Where-Klausel.
22.09.2009
FalkP 3,3k 3 8
FalkP 3,3k 3 8
Die Zeitraumangabe kann auch in der Where-Klausel stehen (in MSSQL).
Floyd 22.09.2009
2
Rein syntaktisch kann sie das. Aber wenn die Zeitraumangabe in der Where-Klausel steht, dann macht das den OUTER JOIN zunichte! Für den Fall das es ein Zimmer ohne Reservierung gibt und damit der OUTER JOIN auf r.zimmernummer = z.zimmernummer greift, sind r.abreisedatum und r.anreisedatum NULL. Ein Vergleich in der Where-Klausel führt dann zum Ausschluß des Datensatzes und eliminiert damit den OUTER JOIN. Und das sollte auch beim MSSQL so sein.
FalkP 22.09.2009
0
Ich halte es für sinnvoller die beiden Tabellen zu joinen.

SELECT r.zimmernummer FROM zimmer AS z LEFT JOIN reservierungen AS r ON z.zimmernummer=r.zimmernummer WHERE anreisedatum<=Abreise AND abreisedatum>=Anreise AND status != "2" GROUP BY zimmernummer;

Für das "=" gilt nach wie vor, das es anforderungsabhängig auch weggelassen werden kann
19.09.2009
huckepick 887 2 8
Hierzu muß der LEFT JOIN aber anders formuliert werden, da sonst Zimmer die überhaupt KEINE Reservierung haben niemals als Frei gezählt werden. Also entweder ein zstzl. OR r.zimmernummer IS NULL (mit passender Klammerung natürlich) oder die Bedingungen in den ON-Teil der JOIN-Definition und nicht in die WHERE-Klausel.
FalkP 21.09.2009
OK, mein erster Kommentar ist quatsch, da dieser JOIN nicht die freien, sondern die belegten Zimmer findet. Für diesen Fall ist der LEFT JOIN jedoch unsinnig, hier würde ein INNER JOIN reichen.
FalkP 21.09.2009
So ganz falsch ist der erste Kommentar von FalkP nicht: Der Join aus der Antwort ist falsch. Statt "WHERE" muss es "AND" heißen und es bedarf noch ein "WHERE r.zimmernzimmer IS NULL". Da ist die Antwort von cyper doch besser lesbar.
BeachBlocker 21.09.2009
Einen Inner Join halte ich für unsinnig, da der die Ergebnistabelle kleiner macht als sie sein soll, da er tatsächlich nur Zimmer liefert, für die Reservierungen vorhanden sind.

Der Left Join enthält alle Zimmer die nicht, oder nicht zu diesem Zeitraum reserviert sind. Bei gar nicht reservierten bleiben Spalten leer, da nur die Zimmernummer abgefragt wird ist das egal.

Ich halte einen Join für besser, weil dadurch nur eine query nötig ist.

Warum das WHERE ein AND sein sollte leuchtet mir nicht ein, den Bestandteil des Joins ist es nicht.

huckepick 21.09.2009
das "on z.zimmernummer=r.zimmernumme AND anreisedatum<=Abreise AND abreisedatum>=Anreise AND status != '2'" sorgt dafür, dass die Bedingung vor und nicht nach dem join augewertet wird. Es werden nur die Reservierung gejoined, die der Bedingung entsprechen und nicht alle Reservierungen und dann erst das where ausgewertet. Beispiele

Zimmer Reservisungen/Status Ergebnis WHERE/AND
1 keine gleich
2 nur außerhalb des Zeitraums unterschiedlich
3 nur innerhalb des Zeitraums gleich
3 innerhalb und außerhalb gleich
BeachBlocker 21.09.2009
0
..........
02.11.2017
muffi 1,4k 1 9
0
..........
29.11.2017
muffi 1,4k 1 9

Stelle deine Sql-Frage jetzt!