Як зберігати ціни, які мають ефективні дати?


21

У мене є список товарів. Кожен з них пропонується N провайдерами.

Кожен провайдер котирує нам ціну на конкретну дату. Ця ціна діє, поки цей постачальник не вирішить встановити нову ціну. У такому випадку постачальник надасть нову ціну з новою датою.

Наразі заголовок таблиці MySQL виглядає так:

provider_id, product_id, price, date_price_effective

Кожен день ми складаємо список товарів / цін, які діють на поточний день. Для кожного продукту список містить відсортований список постачальників, які мають саме цей продукт. Таким чином, ми можемо замовити певні продукти у того, хто трапиться, щоб запропонувати найкращу ціну.

Щоб отримати ефективні ціни, у мене є оператор SQL, який повертає всі рядки, які є date_price_effective >= NOW(). Цей набір результатів обробляється сценарієм ruby, який виконує сортування та фільтрування, необхідні для отримання файлу, який виглядає приблизно так:

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

Це чудово працює для наших цілей, але я все одно відчуваю свербіж, що таблиця SQL - це, мабуть, не найкращий спосіб зберігання подібної інформації. У мене є таке відчуття, що подібні проблеми вирішувалися раніше іншими творчими способами.

Чи є кращий спосіб зберігати цю інформацію, крім того, у SQL? або, якщо ви використовуєте SQL, чи є кращий підхід, ніж той, який я використовую?


lal00: ​​Як я вже згадував в одному зі своїх коментарів, я регулярно обробляю ефективні побачення. Будь ласка, дивіться мою відповідь про простий ефективний метод обробки дати. Це не вимагає того, щоб знати період, коли ціна діє при створенні нового цінового ряду, а також не вимагає повернення модифікації попереднього самого поточного рядка, коли створюється новий рядок.
біт-твідлер

Відповіді:


17

Для предметів, які змінюються залежно від часу (наприклад, можливість відповідати на такі речі, як "яка ціна X на дату D" або "яка корова була в кормах Q на дату E"), я рекомендую прочитати книгу "Розробка орієнтована на час Програми бази даних у SQL. " Незважаючи на те, що ця книга не надрукована, автор люб’язно зробив доступним PDF-книгу книги, а також відповідний компакт-диск на своєму веб-сайті.

http://www.cs.arizona.edu/~rts/publications.html (шукайте перший пункт у розділі "книги").

Коротке ознайомлення в Інтернеті див.


1
Ну, це не те, що я мав на увазі, коли запитав, це краще! :)
edmz

3

Я, безумовно, зберігаю ефективну дату в базі даних. Зрештою, ймовірно, що люди захочуть мати змогу запускати запити, щоб побачити, як ціна змінилася з часом, або перехресно перевірити дивацтва в замовленнях проти історичної таблиці цін на товар. Залежно від типу запитів, які ви виконуєте, та частоти зміни цін, може бути доцільним створення окремих таблиць для поточної ціни та попередніх цін.

У більшості систем, що зберігають ціни, ви хочете, щоб стовпець дати закінчення терміну придатності на додаток до дати набуття чинності, щоб було легше визначити, яка ціна діє в даний час, оскільки це економить вам проблеми перегляду попереднього чи наступного рядка для з'ясування яка ціна діяла в даний момент часу. Мені не зрозуміло, чим NOW() >= date_price_effectiveзаймається ваш стан - мабуть, це повертає поточну ціну разом з усіма попередніми історичними цінами, які мені здаються дивними. Я думаю, що "ефективна ціна" - це поточна ціна, яка визначатиметься чимось на кшталтNOW() BETWEEN date_price_effective AND date_price_expired

Я також не впевнений, як має виглядати ваш файл. Мені не зрозуміло, що provider_1являє собою - провайдер_id = 1 ціна? - або як ви замовляєте дані провайдера - чому вони provider_1з’являються першими product_id_1і третіми для product_id_2.


Джастін, термін придатності має сенс. Ви мали рацію, у мене був SQL навпаки. Вихідний файл не дуже стосується мого питання, я просто додав як спосіб пояснити, що мені потрібно сортувати продукти за ціною.
edmz

Не потрібно включати дату закінчення терміну дії в кожному рядку, оскільки це лише додає додаткові накладні витрати, оскільки зазвичай не дається період, коли ціна діє при створенні рядка. Якщо у таблиці є N рядків для кожної пари produce_id / product_id, кожен з яких діє на певну дату, рядок з найбільшим значенням date_price_effective, що менше або рівний, ніж дана дата, - це ціна, яка діє на цієї дати. Якщо ви подивитесь на мою публікацію, ви побачите код SQL, який виконує такий тип запиту. Доводиться регулярно мати справу з ефективними датами.
біт-трейдлер

@ bit-twiddler - Безумовно, не потрібно мати термін придатності. Однак наявність терміну придатності зазвичай робить запити по таблиці набагато простішими та ефективнішими. Оскільки ефективні запити на дату, як правило, набагато частіше, ніж зміни цін, це, як правило, я радо робити.
Джастін Печера

3

Якщо я правильно розумію ваше завдання проблеми, вам потрібен спосіб обробки даних про покоління (тобто, таблиця містить кілька рядків для кожної пари провайдера_id / product_id, кожен з яких визначає дату). У такому випадку ви шукаєте найсвіжішу ціну на продукт із значенням date_price_effective, меншим або рівним сьогоднішньому. Цей тип ситуації легко обробляється за допомогою підвідбору 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() 
     );

Ціна діє до тих пір, поки вона має найбільше значення date_price_effective, яке менше або рівне даті виконання запиту. Значення date_price_effective, яке більше, ніж сьогодні, - це майбутня дата набуття чинності. Код, перерахований вище, повертає дані рядків для кожної пари провайдера_id / product_id, яка має значення date_price_effective, яке є найближчим до, але не пізніше дати виконання запиту. Рішення автоматично розбиває ціни на ефективні діапазони дат. Первинним ключем для цієї таблиці буде потрійний {provider_id, product_id, date_price_effective};

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.