¿Cómo almacenar precios que tienen fechas de vigencia?

21

Tengo una lista de productos. Cada uno de ellos es ofrecido por N proveedores.

Cada proveedor nos cotiza un precio para una fecha específica. Ese precio es efectivo hasta que ese proveedor decida establecer un nuevo precio. En ese caso, el proveedor le dará el nuevo precio con una nueva fecha.

El encabezado de la tabla MySQL actualmente se ve así:

provider_id, product_id, price, date_price_effective

Cada dos días, compilamos una lista de productos / precios que son efectivos para el día actual. Para cada producto, la lista contiene una lista ordenada de los proveedores que tienen ese producto en particular. De esa manera, podemos ordenar ciertos productos de quien sea que ofrezca el mejor precio.

Para obtener los precios efectivos, tengo una instrucción SQL que devuelve todas las filas que tienen date_price_effective >= NOW(). Ese conjunto de resultados se procesa con un script ruby ​​que realiza la clasificación y el filtrado necesarios para obtener un archivo que se ve así:

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

Esto funciona bien para nuestros propósitos, pero todavía tengo ganas de que una tabla SQL probablemente no sea la mejor manera de almacenar este tipo de información. Tengo la sensación de que este tipo de problema se ha resuelto previamente de otras maneras más creativas.

¿Hay una mejor manera de almacenar esta información que no sea en SQL? o, si usa SQL, ¿hay un mejor enfoque que el que estoy usando?

edmz
fuente
lal00: ​​Como mencioné en uno de mis comentarios, manejo las citas efectivas de manera regular. Por favor vea mi respuesta para un método simple de manejo efectivo de la fecha. No requiere que uno sepa el período en que un precio es efectivo cuando se crea una nueva fila de precios, ni requiere que uno retroceda y modifique la fila más actual anterior cuando se crea una nueva fila.
bit-twiddler

Respuestas:

17

Para los ítems que varían según el tiempo (como poder responder cosas como "cuál era el precio de X en la fecha D" o "qué vaca estaba en el corral de engorde Q en la fecha E"), recomiendo leer el libro "Desarrollo orientado al tiempo Aplicaciones de bases de datos en SQL ". Mientras este libro está agotado, el autor ha puesto a disposición el PDF del libro y el CD asociado en su sitio web.

http://www.cs.arizona.edu/~rts/publications.html (busque el primer elemento en "libros").

Para una breve introducción en línea, consulte:

Tangurena
fuente
1
Bueno, esto no es lo que tenía en mente cuando pregunté, ¡es mejor! :)
edmz
3

Ciertamente almacenaría la fecha de vigencia en la base de datos. Después de todo, es probable que las personas quieran poder realizar consultas para ver cómo ha cambiado el precio con el tiempo o para verificar las rarezas en los pedidos contra la tabla de precios histórica del producto. Dependiendo del tipo de consultas que esté ejecutando y la frecuencia de los cambios de precios, puede tener sentido tener tablas separadas para el precio actual y los precios históricos.

En la mayoría de los sistemas que almacenan precios, querrá una columna de fecha de vencimiento además de la fecha de vigencia para que sea más fácil determinar qué precio está actualmente vigente, ya que le ahorra la molestia de tener que mirar la fila anterior o siguiente para calcular fuera de qué precio estaba vigente en un momento dado. No tengo claro qué NOW() >= date_price_effectiveestá haciendo su condición, presumiblemente, eso devuelve el precio actual junto con todos los precios históricos anteriores, lo que me parece extraño. Yo pensaría que el "precio efectivo" sería el precio actual que se definiría por algo comoNOW() BETWEEN date_price_effective AND date_price_expired

Tampoco estoy seguro de cómo debe verse su archivo. No está claro para mí lo que provider_1represents-- la PROVIDER_ID = 1 precio -? O cómo se está ordenando el proveedor de Data-- ¿por qué provider_1aparece primero para product_id_1y el tercero para product_id_2.

Justin Cave
fuente
Justin, la fecha de vencimiento tiene sentido. Tenías razón, tenía el SQL al revés. El archivo de salida no es muy relevante para mi pregunta, solo agregué como una forma de ejemplificar que necesitaba clasificar los productos por precio.
edmz
No es necesario incluir una fecha de vencimiento en cada fila, ya que hacerlo solo agrega una sobrecarga adicional, ya que generalmente no se le da el período en que un precio es efectivo cuando se crea la fila. Si tenemos N filas para cada par productor_id / producto_id en una tabla, cada una de las cuales es efectiva en una fecha determinada, la fila con el mayor valor date_price_effective que sea menor o igual que una fecha dada es el precio que está vigente en esa fecha. Si miras mi publicación, verás un código SQL que realiza este tipo de consulta. Tengo que lidiar con fechas efectivas de forma regular.
bit-twiddler
@ bit-twiddler: ciertamente, no es necesario tener una fecha de vencimiento. Sin embargo, tener una fecha de vencimiento generalmente hace que consultar la tabla sea mucho más fácil y eficiente. Dado que las consultas de fechas efectivas son generalmente mucho más comunes que los cambios de precios, generalmente es una compensación que estoy feliz de hacer.
Justin Cave
3

Si entiendo su enunciado del problema correctamente, necesita una forma de manejar los datos generacionales (es decir, la tabla contiene varias filas para cada par de id_productor / id_producto, cada una de las cuales es sensible a la fecha). En ese caso, está buscando el precio más reciente para un producto con un valor date_price_effective que sea menor o igual que hoy. Este tipo de situación se maneja fácilmente utilizando una subselección 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 precio es efectivo siempre que tenga el mayor valor date_price_effective que sea menor o igual que la fecha en que se ejecuta la consulta. Un valor date_price_effective que es mayor que hoy es una fecha efectiva futura. El código enumerado anteriormente devuelve los datos de la fila para cada par proveedor_id / producto_id que tiene el valor date_price_effective que es el más cercano, pero no posterior a la fecha en que se ejecuta la consulta. La solución pone automáticamente los precios en intervalos de fechas efectivos. La clave principal para esta tabla sería el triple {provider_id, product_id, date_price_effective};

bit-twiddler
fuente