Для личного проекта, над которым я сейчас работаю, я хочу составить линейный график цен на игры в Steam, Impulse, EA Origins и некоторых других сайтах с течением времени. На данный момент я изменил скрипт, используемый SteamCalculator.com для записи текущей цены (продажной цены, если применимо) для каждой игры в каждом возможном коде страны или на каждом из этих сайтов. У меня также есть столбец для даты, в которую была сохранена цена. Мои текущие таблицы выглядят примерно так:
THIS STRUCTURE IS NO LONGER VALID. SEE BELOW
+----------+------+------+------+------+------+------+------------+
| steam_id | us | at | au | de | no | uk | date |
+----------+------+------+------+------+------+------+------------+
| 112233 | 999 | 899 | 999 | NULL | 899 | 699 | 2011-8-21 |
| 123456 | 1999 | 999 | 1999 | 999 | 999 | 999 | 2011-8-20 |
| ... | ... | ... | ... | ... | ... | ... | ... |
+----------+------+------+------+------+------+------+------------+
В настоящее время каждая страна обновляется отдельно (существует цикл for, проходящий через страны), хотя, если это упростит ее, ее можно изменить, чтобы временно сохранить новые цены в массиве, а затем обновлять всю строку за раз. Скорее всего, в конечном итоге я буду делать это по соображениям производительности.
Теперь моя проблема - определить, как лучше всего обновить эту таблицу, если одна из цен изменится. Например, предположим, что 22.08.2011 игра 112233
поступит в продажу в Америке за 4,99 доллара, в Австрии за 3,99 евро, а остальные цены останутся прежними. Мне нужно, чтобы таблица выглядела так:
THIS STRUCTURE IS NO LONGER VALID. SEE BELOW
+----------+------+------+------+------+------+------+------------+
| steam_id | us | at | au | de | no | uk | date |
+----------+------+------+------+------+------+------+------------+
| 112233 | 999 | 899 | 999 | NULL | 899 | 699 | 2011-8-21 |
| 123456 | 1999 | 999 | 1999 | 999 | 999 | 999 | 2011-8-20 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 112233 | 499 | 399 | 999 | NULL | 899 | 699 | 2011-8-22 |
+----------+------+------+------+------+------+------+------------+
Я не хочу создавать новую строку КАЖДЫЙ во время проверки цены, в противном случае я получу миллионы строк повторяющихся цен день за днем. Я также не хочу создавать новую строку за измененную цену, например:
THIS STRUCTURE IS NO LONGER VALID. SEE BELOW
+----------+------+------+------+------+------+------+------------+
| steam_id | us | at | au | de | no | uk | date |
+----------+------+------+------+------+------+------+------------+
| 112233 | 999 | 899 | 999 | NULL | 899 | 699 | 2011-8-21 |
| 123456 | 1999 | 999 | 1999 | 999 | 999 | 999 | 2011-8-20 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 112233 | 499 | 899 | 999 | NULL | 899 | 699 | 2011-8-22 |
| 112233 | 499 | 399 | 999 | NULL | 899 | 699 | 2011-8-22 |
+----------+------+------+------+------+------+------+------------+
Я могу предотвратить первую проблему, но не вторую, сделав каждый (steam_id, <country>)
уникальным индексом, а затем добавив ON DUPLICATE KEY UPDATE
к каждому запросу базы данных. Это только добавит строку, если цена будет отличаться, однако добавит новую строку для каждой страны, которая меняется. Он также не допускает одинаковую цену для одной игры в течение двух разных дней (например, предположим, что игра 112233
поступит в продажу позже и вернется к $ 9,99), так что это явно ужасный вариант.
Я могу предотвратить вторую проблему, но не первую, сделав (steam_id, date)
уникальным индексом и добавив ON DUPLICATE KEY UPDATE
к каждому запросу. Каждый день, когда запускается скрипт, дата менялась, поэтому он будет создавать новую строку. Этот метод заканчивается сотнями строк с одинаковыми ценами изо дня в день.
Как я могу сказать MySQL создать новую строку, если (и только если) какая-либо из цен изменилась с самой последней даты?
ОБНОВЛЕНИЕ -
По рекомендации участников этой ветки я изменил схему своей базы данных, чтобы облегчить добавление новых кодов стран в будущем и избежать необходимости обновлять целые строки за раз. Новая схема выглядит примерно так:
+----------+------+---------+------------+
| steam_id | cc | price | date |
+----------+------+---------+------------+
| 112233 | us | 999 | 2011-8-21 |
| 123456 | uk | 699 | 2011-8-20 |
| ... | ... | ... | ... |
+----------+------+---------+------------+
Вдобавок к этой новой схеме я обнаружил, что могу использовать следующий SQL-запрос, чтобы получить цену от самого последнего обновления:
SELECT `price` FROM `steam_prices` WHERE `steam_id` = 112233 AND `cc`='us' ORDER BY `date` ASC LIMIT 1
На данный момент мой вопрос сводится к следующему:
Можно ли (используя только SQL, а не логику приложения) вставить строку, только если условие истинно? Например:
INSERT INTO `steam_prices` (...) VALUES (...) IF price<>(SELECT `price` FROM `steam_prices` WHERE `steam_id` = 112233 AND `cc`='us' ORDER BY `date` ASC LIMIT 1)
С руководство по MySQL Не могу найти способ сделать это. Я обнаружил, что вы можете игнорировать или обновить, если уникальный индекс совпадает. Однако, если бы я сделал цену уникальным индексом (что позволило бы мне обновить дату, если она была такой же), я бы не смог распознать, когда игра поступила в продажу, а затем вернулся к своей первоначальной цене. Например:
+----------+------+---------+------------+
| steam_id | cc | price | date |
+----------+------+---------+------------+
| 112233 | us | 999 | 2011-8-20 |
| 112233 | us | 499 | 2011-8-21 |
| 112233 | us | 999 | 2011-8-22 |
| ... | ... | ... | ... |
+----------+------+---------+------------+
Кроме того, после того, как я только нашел и прочитал Условная вставка MySQL , я создал и попробовал следующий запрос:
INSERT INTO `steam_prices`(
`steam_id`,
`cc`,
`update`,
`price`
)
SELECT '7870', 'us', NOW(), 999
FROM `steam_prices`
WHERE
`price`<>999
AND `update` IN (
SELECT `update`
FROM `steam_prices`
ORDER BY `update`
ASC LIMIT 1
)
Идея состояла в том, чтобы вставить строку '7870', 'us', NOW(), 999
, если (и только если) price
самого последнего update
не было 999. Когда я запустил это, я получил следующую ошибку:
1235 - Эта версия MySQL еще не поддерживает подзапрос «LIMIT & IN / ALL / ANY / SOME» *
Есть идеи?