我的桌子看起来像这样:
mysql> explain test_table;
+---------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+-------+
| timestamp | datetime | NO | PRI | NULL | |
| id | varchar(64) | NO | PRI | NULL | |
| px_last | float | NO | | NULL | |
| twap | float | YES | | NULL | |
+---------------------+-------------+------+-----+---------+-------+
对于给定的符号和时间戳,我想将字段twap
的值向后移一步。
此表:
mysql> select * from test_table;
+---------------------+-------+---------+-------+
| timestamp | id | px_last | twap |
+---------------------+-------+---------+-------+
| 2011-01-01 00:00:00 | apple | 101 | 101.1 |
| 2011-01-01 00:00:00 | pear | 50 | 50.1 |
| 2011-01-02 00:00:00 | apple | 102 | 112.8 |
| 2011-01-02 00:00:00 | pear | 51 | 57.3 |
| 2011-01-03 00:00:00 | pear | 52 | 59.1 |
| 2011-01-03 00:00:00 | apple | 103 | 104.1 |
+---------------------+-------+---------+-------+
应该像这样结束:
mysql> select * from test_table;
+---------------------+-------+---------+-------+
| timestamp | id | px_last | twap |
+---------------------+-------+---------+-------+
| 2011-01-01 00:00:00 | apple | 101 | 112.8 |
| 2011-01-01 00:00:00 | pear | 50 | 57.3 |
| 2011-01-02 00:00:00 | apple | 102 | 104.1 |
| 2011-01-02 00:00:00 | pear | 51 | 59.1 |
| 2011-01-03 00:00:00 | pear | 52 | NULL |
| 2011-01-03 00:00:00 | apple | 103 | NULL |
+---------------------+-------+---------+-------+
我的第一种方法(使用此示例:How to number rows...)将在每个符号中创建行号(1,2 .... n),然后将行号,符号和twap复制到临时表,减少临时表中每行的行号,然后将数据复制回原始表。
有没有办法在不创建临时表的情况下执行此操作?表格很大,> 5000万行并且不断增长,因此找到小于给定时间戳的最大时间戳是不够有效的。
答案 0 :(得分:1)
你可以写:
UPDATE test_table tt1
SET tt1.twap =
( SELECT tt2.twap
FROM ( SELECT timestamp,
id,
twap
FROM test_table
) tt2
WHERE tt2.timestamp = DATE_ADD(tt1.timestamp, INTERVAL 1 DAY)
AND tt2.id = tt1.id
)
;
从技术上讲,这个会创建一个临时表(作为可怕的ERROR 1093 (HY000): You can't specify target table 'tt1' for update in FROM clause
的解决方法),但至少它是由内部子查询隐式处理的,而不是要求你创建一个单独的步骤。
对于大型桌子,我不希望它表现得非常好,但你可以通过一次处理一个时间范围将其分解为更小的更新(假设你从最早的时间范围开始并向后移动,这样你就永远不会覆盖你将要使用的数据。您的个人陈述将如下所示:
UPDATE test_table tt1
SET tt1.twap =
( SELECT tt2.twap
FROM ( SELECT timestamp,
id,
twap
FROM test_table
WHERE timestamp BETWEEN TIMESTAMP '2011-01-02 00:00:00'
AND TIMESTAMP '2011-02-01 23:59:59'
) tt2
WHERE tt2.timestamp = DATE_ADD(tt1.timestamp, INTERVAL 1 DAY)
AND tt2.id = tt1.id
)
WHERE tt1.timestamp BETWEEN TIMESTAMP '2011-01-01 00:00:00'
AND TIMESTAMP '2011-01-31 23:59:59'
;