Comment stocker des prix ayant des dates de validité?

21

J'ai une liste de produits. Chacun d'eux est proposé par N prestataires.

Chaque fournisseur nous propose un prix pour une date précise. Ce prix est effectif jusqu'à ce que le fournisseur décide de fixer un nouveau prix. Dans ce cas, le fournisseur donnera le nouveau prix avec une nouvelle date.

L'en-tête de table MySQL ressemble actuellement à:

provider_id, product_id, price, date_price_effective

Tous les deux jours, nous établissons une liste de produits / prix en vigueur pour la journée en cours. Pour chaque produit, la liste contient une liste triée des fournisseurs qui ont ce produit particulier. De cette façon, nous pouvons commander certains produits à quiconque vous propose le meilleur prix.

Pour obtenir les prix effectifs, j'ai une instruction SQL qui renvoie toutes les lignes qui en ont date_price_effective >= NOW(). Cet ensemble de résultats est traité avec un script ruby ​​qui effectue le tri et le filtrage nécessaires pour obtenir un fichier qui ressemble à ceci:

product_id_1,provider_1,provider_3,provider8,provider_10...
product_id_2,provider_3,provider_2,provider1,provider_10...

Cela fonctionne bien pour nos besoins, mais j'ai toujours la démangeaison qu'une table SQL n'est probablement pas la meilleure façon de stocker ce type d'informations. J'ai le sentiment que ce genre de problème a été résolu auparavant par d'autres moyens plus créatifs.

Existe-t-il un meilleur moyen de stocker ces informations autrement qu'en SQL? ou, si vous utilisez SQL, y a-t-il une meilleure approche que celle que j'utilise?

edmz
la source
lal00: ​​Comme je l'ai mentionné dans un de mes commentaires, je gère régulièrement les rencontres efficaces. Veuillez consulter ma réponse pour une méthode simple et efficace de gestion des dates. Il ne nécessite pas de connaître la période pendant laquelle un prix est effectif lorsqu'une nouvelle ligne de prix est créée, ni de revenir en arrière et de modifier la ligne la plus récente précédente lorsqu'une nouvelle ligne est créée.
bit-twiddler

Réponses:

17

Pour les éléments qui varient en fonction du temps (comme être en mesure de répondre à des questions comme «quel était le prix de X à la date D» ou «quelle vache était dans le parc d'engraissement Q à la date E»), je recommande de lire le livre «Developing Time-Oriented Applications de base de données en SQL. " Bien que ce livre soit épuisé, l'auteur a gracieusement mis à disposition le PDF du livre ainsi que le CD associé sur son site Web.

http://www.cs.arizona.edu/~rts/publications.html (recherchez le premier élément sous "livres").

Pour une brève introduction en ligne, voir:

Tangurena
la source
1
Bon, ce n'est pas ce que j'avais en tête quand j'ai demandé, c'est mieux! :)
edmz
3

Je conserverais certainement la date d'entrée en vigueur dans la base de données. Après tout, il est probable que les gens voudront pouvoir exécuter des requêtes pour voir comment le prix a changé au fil du temps ou pour recouper les bizarreries des commandes par rapport au tableau historique des prix des produits. Selon le type de requêtes que vous exécutez et la fréquence des changements de prix, il peut être judicieux d'avoir des tableaux séparés pour le prix actuel et les prix historiques.

Dans la plupart des systèmes qui stockent les prix, vous voudriez une colonne de date d'expiration en plus de la date effective pour faciliter la détermination du prix actuellement en vigueur car cela vous évite d'avoir à regarder la ligne précédente ou suivante pour figurer quel prix était en vigueur à un moment donné. Je ne sais pas exactement ce que fait votre NOW() >= date_price_effectiveétat - sans doute, qui renvoie le prix actuel avec tous les prix historiques antérieurs, ce qui me semble étrange. Je pense que le "prix effectif" serait le prix actuel qui serait défini par quelque chose commeNOW() BETWEEN date_price_effective AND date_price_expired

Je ne sais pas non plus à quoi votre fichier est censé ressembler. Pour moi, ce que provider_1représente - le prix provider_id = 1? - ni comment vous commandez les données du fournisseur - pourquoi provider_1apparaît en premier pour product_id_1et en troisième pour product_id_2?

Justin Cave
la source
Justin, la date d'expiration est logique. Vous aviez raison, j'avais le SQL dans l'autre sens. Le fichier de sortie n'est pas très pertinent pour ma question, j'ai juste ajouté comme un exemple pour montrer que j'avais besoin de trier les produits par prix.
edmz
Il n'est pas nécessaire d'inclure une date d'expiration dans chaque ligne, car cela ne fait qu'ajouter des frais généraux supplémentaires, car on n'a généralement pas la période pendant laquelle un prix est effectif lorsque la ligne est créée. Si nous avons N lignes pour chaque paire producteur_id / produit_id dans une table, chacune étant effective à une certaine date, la ligne avec la plus grande valeur date_price_effective qui est inférieure ou égale à une date donnée est le prix qui est en vigueur le cette date. Si vous regardez ma publication, vous verrez du code SQL qui effectue ce type de requête. Je dois m'occuper régulièrement des dates d'entrée en vigueur.
bit-twiddler
@ bit-twiddler - Certes, il n'est pas nécessaire d'avoir une date d'expiration. Cependant, avoir une date d'expiration rend généralement l'interrogation de la table beaucoup plus facile et plus efficace. Étant donné que les requêtes de dates effectives sont généralement beaucoup plus courantes que les changements de prix, c'est généralement un compromis que je suis heureux de faire.
Justin Cave
3

Si je comprends bien votre énoncé de problème, vous avez besoin d'un moyen de gérer les données générationnelles (c'est-à-dire que la table contient plusieurs lignes pour chaque paire provider_id / product_id dont chacune est sensible à la date). Dans ce cas, vous recherchez le prix le plus récent pour un produit dont la valeur date_price_effective est inférieure ou égale à aujourd'hui. Ce type de situation est facile à gérer à l'aide d'une sous-sélection SQL.

 SELECT 
   provider_id, product_id, price, date_price_effective 
 FROM 
   price_table a 
 WHERE 
   date_price_effective = 
     (
       SELECT 
         MAX(date_price_effective) 
       FROM 
         price_table b 
       WHERE 
         b.provider_id = a.provider_id AND 
         b.product_id = a.product_id AND
         b.date_price_effective <= NOW() 
     );

Un prix est effectif tant qu'il a la plus grande valeur date_price_effective inférieure ou égale à la date d'exécution de la requête. Une valeur date_price_effective supérieure à aujourd'hui est une date effective future. Le code répertorié ci-dessus renvoie les données de ligne pour chaque paire provider_id / product_id dont la valeur date_price_effective est la plus proche, mais pas plus tard que la date d'exécution de la requête. La solution place automatiquement les prix dans des plages de dates effectives. La clé primaire de cette table serait le triple {provider_id, product_id, date_price_effective};

bit-twiddler
la source