0

次のようなテーブルがあります。

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    |       |
+---------------------+-------------+------+-----+---------+-------+

特定のシンボルとタイムスタンプについて、フィールドの値をtwap1 タイムステップ戻します。

この表:

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 を一時テーブルにコピーすることです。一時テーブルの各行で行番号を 1 ずつ減らしてから、データを元のテーブルにコピーして戻します。

一時テーブルを作成せずにこれを行う方法はありますか? テーブルは巨大で、5,000 万行を超えて増加しているため、特定のタイムスタンプよりも小さい最大のタイムスタンプを見つけることは十分に効率的ではありません。

4

1 に答える 1

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) が、少なくとも、別のステップとしてテーブルを作成する必要はなく、内部サブクエリによってすべて暗黙的に処理されます。

大きなテーブルの場合、これがうまく機能するとは思いませんが、一度に 1 つの時間範囲だけを処理することで、小さな更新に分割できます (ただし、最も早い時間範囲から開始し、将来に向かって移動することを条件とします)。使用しようとしているデータを上書きしないでください)。個々のステートメントは次のようになります。

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'
;
于 2012-11-29T20:22:23.317 に答える