Meine DBA-Erfahrung geht nicht viel weiter als das einfache Speichern und Abrufen von Daten im CMS-Stil - dies kann also eine dumme Frage sein, ich weiß es nicht!
Ich habe ein Problem, bei dem ich die Urlaubspreise für eine bestimmte Gruppengröße und eine bestimmte Anzahl von Tagen innerhalb eines bestimmten Zeitraums nachschlagen oder berechnen muss. Z.B:
Wie viel kostet ein Hotelzimmer für 2 Personen für 4 Nächte im Januar?
Ich habe Preis- und Verfügbarkeitsdaten für beispielsweise 5000 Hotels, die wie folgt gespeichert sind:
Hotel ID | Date | Spaces | Price PP
-----------------------------------
123 | Jan1 | 5 | 100
123 | Jan2 | 7 | 100
123 | Jan3 | 5 | 100
123 | Jan4 | 3 | 100
123 | Jan5 | 5 | 100
123 | Jan6 | 7 | 110
456 | Jan1 | 5 | 120
456 | Jan2 | 1 | 120
456 | Jan3 | 4 | 130
456 | Jan4 | 3 | 110
456 | Jan5 | 5 | 100
456 | Jan6 | 7 | 90
Mit dieser Tabelle kann ich eine Abfrage wie folgt durchführen:
SELECT hotel_id, sum(price_pp)
FROM hotel_data
WHERE
date >= Jan1 and date <= Jan4
and spaces >= 2
GROUP BY hotel_id
HAVING count(*) = 4;
Ergebnisse
hotel_id | sum
----------------
123 | 400
Die HAVING
Klausel hier stellt sicher, dass für jeden einzelnen Tag zwischen meinen gewünschten Daten ein Eintrag vorhanden ist, für den die verfügbaren Plätze verfügbar sind. dh. Das Hotel 456 hatte am 2. Januar 1 freien Platz, die HAVING-Klausel würde 3 zurückgeben, sodass wir für das Hotel 456 kein Ergebnis erhalten.
So weit, ist es gut.
Gibt es jedoch eine Möglichkeit, alle 4 Nachtperioden im Januar herauszufinden, in denen Platz verfügbar ist? Wir könnten die Abfrage 27 Mal wiederholen und die Daten jedes Mal erhöhen, was etwas umständlich erscheint. Oder ein anderer Weg könnte darin bestehen, alle möglichen Kombinationen in einer Nachschlagetabelle wie folgt zu speichern:
Hotel ID | total price pp | num_people | num_nights | start_date
----------------------------------------------------------------
123 | 400 | 2 | 4 | Jan1
123 | 400 | 2 | 4 | Jan2
123 | 400 | 2 | 4 | Jan3
123 | 400 | 3 | 4 | Jan1
123 | 400 | 3 | 4 | Jan2
123 | 400 | 3 | 4 | Jan3
Und so weiter. Wir müssten die maximale Anzahl von Nächten und die maximale Anzahl von Personen, nach denen wir suchen würden, begrenzen - z. B. maximale Anzahl von Nächten = 28, maximale Anzahl von Personen = 10 (begrenzt auf die Anzahl der verfügbaren Plätze für diesen festgelegten Zeitraum ab diesem Datum).
Für ein Hotel könnten wir 28 * 10 * 365 = 102000 Ergebnisse pro Jahr erzielen. 5000 Hotels = 500 Millionen Ergebnisse!
Aber wir hätten eine sehr einfache Frage, um den günstigsten 4-Nächte-Aufenthalt im Januar für 2 Personen zu finden:
SELECT
hotel_id, start_date, price
from hotel_lookup
where num_people=2
and num_nights=4
and start_date >= Jan1
and start_date <= Jan27
order by price
limit 1;
Gibt es eine Möglichkeit, diese Abfrage für die ursprüngliche Tabelle durchzuführen, ohne die 500-m-Zeilen-Nachschlagetabelle generieren zu müssen? zB die 27 möglichen Ergebnisse in einer temporären Tabelle oder einer anderen solchen inneren Abfragemagie generieren?
Momentan werden alle Daten in einer Postgres-Datenbank gespeichert. Können wir die Daten bei Bedarf zu einem anderen geeigneten Ort verschieben? Nicht sicher, ob diese Art von Abfrage zu den Map / Reduce-Mustern für DBs im NoSQL-Stil passt ...
quelle
Ein anderer Weg, mit der
LAG()
Funktion:Test bei: SQL-Fiddle
quelle
(spaces, day)
, vielleicht sogar einem abdeckenden Index(spaces, day, hotel_id, price)
.Sie sollten das gewünschte Ergebnis erhalten, ohne zusätzliche Strukturen zu benötigen. Abhängig von der Größe der Eingabedaten, Ihrer Indexstruktur und der Helligkeit des Abfrageplaners kann die innere Abfrage jedoch zu einem Spool auf die Festplatte führen. Möglicherweise finden Sie es jedoch ausreichend effizient. Vorsichtsmaßnahme: Mein Fachwissen
bezieht sich aufMS SQL Server und die Funktionen seines Abfrageplaners.Daher benötigt die obige Syntax möglicherweise zwei Wochen, wenn auch nur in Funktionsnamen(ypercube hat die Syntax so angepasst, dass sie jetzt vermutlich postgres-kompatibel ist, siehe Antwortverlauf für die TSQL-Variante) .Die oben genannten finden Aufenthalte, die im Januar beginnen, aber bis in den Februar hinein andauern. Das Hinzufügen einer zusätzlichen Klausel zum Datumstest (oder das Anpassen des Enddatumswerts) kann dies problemlos beheben, wenn dies nicht erwünscht ist.
quelle
Unabhängig von HotelID können Sie eine Summiertabelle mit einer berechneten Spalte wie folgt verwenden:
Diese Tabelle enthält keine Primär- oder Fremdschlüssel, da sie nur zur schnellen Berechnung mehrerer Wertekombinationen verwendet wird. Wenn Sie mehr als einen berechneten Wert benötigen oder möchten, erstellen Sie eine neue Ansicht mit einem neuen Ansichtsnamen für jeden Monatswert in Kombination mit jedem der Personen- und Preis-PP-Werte:
PSEUDO-CODE-BEISPIEL
SummedColumn = 2400
Zuletzt verbinden Sie die Ansicht mit der HotelID. Dazu müssen Sie eine Liste aller HotelIDs in SummingTable speichern (siehe oben), obwohl HotelID nicht zur Berechnung in der Ansicht verwendet wird. Gefällt mir So:
MEHR PSEUDO-CODE
quelle