Mon expérience DBA ne va pas beaucoup plus loin que le simple stockage + récupération de données de style CMS - donc cela peut être une question stupide, je ne sais pas!
J'ai un problème pour lequel je dois rechercher ou calculer les prix des vacances pour une certaine taille de groupe et un certain nombre de jours dans une certaine période de temps. Par exemple:
Combien coûte une chambre d'hôtel pour 2 personnes pour 4 nuits à tout moment en janvier?
J'ai des données de prix et de disponibilité pour, disons, 5000 hôtels stockés comme suit:
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
Avec ce tableau, je peux faire une requête comme ceci:
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;
résultats
hotel_id | sum
----------------
123 | 400
La HAVING
clause ici garantit qu'il y a une entrée pour chaque jour entre mes dates souhaitées qui dispose des espaces disponibles. c'est à dire. L'hôtel 456 avait 1 espace disponible le 2 janvier, la clause HAVING en retournerait 3, donc nous n'avons pas de résultat pour l'hôtel 456.
Jusqu'ici tout va bien.
Cependant, existe-t-il un moyen de connaître toutes les 4 périodes de nuit en janvier où il y a de l'espace disponible? Nous pourrions répéter la requête 27 fois - en incrémentant les dates à chaque fois, ce qui semble un peu gênant. Ou une autre solution pourrait être de stocker toutes les combinaisons possibles dans une table de recherche comme ceci:
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
Etc. Nous devons limiter le nombre maximum de nuits et le nombre maximum de personnes que nous recherchons - par exemple, nuits max = 28, personnes max = 10 (limité au nombre de places disponibles pour cette période définie à partir de cette date).
Pour un hôtel, cela pourrait nous donner 28 * 10 * 365 = 102000 résultats par an. 5000 hôtels = 500 m de résultats!
Mais nous aurions une requête très simple pour trouver le séjour de 4 nuits le moins cher à Jan pour 2 personnes:
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;
Existe-t-il un moyen d'effectuer cette requête sur la table initiale sans avoir à générer la table de recherche des lignes de 500 m!? par exemple générer les 27 résultats possibles dans une table temporaire ou une autre magie de requête interne?
Pour le moment, toutes les données sont conservées dans une base de données Postgres - si besoin est, nous pouvons déplacer les données vers quelque chose de plus approprié? Je ne sais pas si ce type de requête correspond aux modèles de carte / réduction pour les bases de données de style NoSQL ...
la source
Une autre façon, en utilisant la
LAG()
fonction:Testez à: SQL-Fiddle
la source
(spaces, day)
, peut-être même un index couvrant(spaces, day, hotel_id, price)
.devrait vous donner le résultat que vous recherchez sans avoir besoin de structures supplémentaires, bien qu'en fonction de la taille des données d'entrée, de votre structure d'index et de la luminosité du planificateur de requêtes, la requête interne peut entraîner une spoule sur le disque. Vous pouvez cependant le trouver suffisamment efficace. Mise en garde: mon expertise concerne MS SQL Server et les capacités de son planificateur de requêtes, de
sorte que la syntaxe ci-dessus peut nécessiter des tweks, uniquement dans les noms de fonction(ypercube a ajusté la syntaxe afin qu'elle soit probablement compatible postgres maintenant, voir l'historique des réponses pour la variante TSQL) .Ce qui précède trouvera des séjours qui commencent en janvier mais se poursuivent en février. L'ajout d'une clause supplémentaire au test de date (ou l'ajustement de la valeur de date de fin entrant) traitera facilement cela si cela n'est pas souhaitable.
la source
Indépendamment de HotelID, vous pouvez utiliser un tableau de sommation, avec une colonne calculée, comme suit:
Il n'y a pas de clés primaires ou étrangères dans ce tableau, car il n'est utilisé que pour calculer rapidement plusieurs combinaisons de valeurs. Si vous avez besoin ou souhaitez plusieurs valeurs calculées, créez une nouvelle vue avec un nouveau nom de vue pour chacune des valeurs du mois en combinaison avec chacune des valeurs PP de personnes et de prix:
EXEMPLE DE CODE PSEUDO
SummedColumn = 2400
Enfin, joignez la vue à l'ID d'hôtel. Pour ce faire, vous devrez stocker une liste de tous les HotelID dans SummingTable (je l'ai fait dans le tableau ci-dessus), même si HotelID n'est pas utilisé pour calculer dans la vue. Ainsi:
PLUS DE CODE PSEUDO
la source