ste*_*esu 2 mysql sql perl sql-update
对于我正在进行的个人项目,我想在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 |
| ... | ... | ... | ... | ... | ... | ... | ... |
+----------+------+------+------+------+------+------+------------+
Run Code Online (Sandbox Code Playgroud)
目前每个国家/地区都是单独更新的(有一个for循环通过这些国家/地区),但如果它会简化它,那么可以修改它以暂时将新价格存储到数组中,然后一次更新整行.无论如何,出于性能原因,我最终可能会这样做.
现在我的问题是确定如果其中一个价格发生变化,如何最好地更新此表.例如,我们假设2011年8月22日该游戏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 |
+----------+------+------+------+------+------+------+------------+
Run Code Online (Sandbox Code Playgroud)
我不希望创建一个新的行EVERY价格检查时间,否则我将结束一天后,有上百万重复价格一天行.我也不想为每个更改的价格创建一个新行,如下所示:
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 |
+----------+------+------+------+------+------+------+------------+
Run Code Online (Sandbox Code Playgroud)
我可以通过使每个问题(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 |
| ... | ... | ... | ... |
+----------+------+---------+------------+
Run Code Online (Sandbox Code Playgroud)
在这个新架构的基础上,我发现我可以使用以下SQL查询来获取最新更新的价格:
SELECT `price` FROM `steam_prices` WHERE `steam_id` = 112233 AND `cc`='us' ORDER BY `date` ASC LIMIT 1
Run Code Online (Sandbox Code Playgroud)
在这一点上,我的问题归结为:
是否可以(仅使用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)
Run Code Online (Sandbox Code Playgroud)
从MySQL手册我找不到任何方法来做到这一点.我发现如果唯一索引相同,您可以忽略或更新.但是,如果我将价格作为一个独特的索引(允许我更新日期,如果它是相同的),那么我将无法识别游戏何时开始销售,然后返回其原始价格.例如:
+----------+------+---------+------------+
| steam_id | cc | price | date |
+----------+------+---------+------------+
| 112233 | us | 999 | 2011-8-20 |
| 112233 | us | 499 | 2011-8-21 |
| 112233 | us | 999 | 2011-8-22 |
| ... | ... | ... | ... |
+----------+------+---------+------------+
Run Code Online (Sandbox Code Playgroud)
此外,在找到并阅读MySQL Conditional INSERT之后,我创建并尝试了以下查询:
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
)
Run Code Online (Sandbox Code Playgroud)
想法是插入行,'7870', 'us', NOW(), 999如果(并且仅当)price最近的行update不是999.当我运行它时,我得到以下错误:
1235 - 此版本的MySQL尚不支持'LIMIT&IN/ALL/ANY/SOME子查询'
有任何想法吗?
如果您只是将模式更改为以下内容,您可能会发现这更容易:
steam_id integer
country varchar(2)
date date
price float
primary key (steam_id,country,date)
Run Code Online (Sandbox Code Playgroud)
(与其他适当的指数)然后只是依次担心每个国家.
换句话说,你的for循环有一个唯一的ID /国家组合,所以它可以简单地查询该组合的最新日期记录,如果它不同则添加一个新行.
这将使您的选择更加复杂,但我相信这是一个更好的解决方案,特别是如果有任何机会可以在未来添加更多国家(在这种情况下不会破坏架构).