MySQLではUPDATE文にLIMITを付けることで、あるテーブルから指定した件数のレコードを更新することができる。 これを応用することで、テーブルからランダムに選んだレコードを更新することもできる。
UPDATE文で件数を指定するには以下のようにする。
UPDATE <テーブル名> SET <カラム名1> = <値1>, <カラム名2> = <値2>, ... WHERE <条件> LIMIT <件数>;
UPDATE counter SET count = count + 1 LIMIT 3; UPDATE user SET score = 0, flag = true WHERE flag = false LIMIT 2;
この場合、取り出された順に指定された件数のレコードが更新されるので、どのデータが更新されるかはわからない。
MySQLではUPDATE文でLIMITだけでなくORDERを付けることもできるので、以下のようにすることでidの小さな方から順に指定した件数のデータを更新することができる。
UPDATE <テーブル名> SET <カラム名1> = <値1>, <カラム名2> = <値2>, ... WHERE <条件> ORDER BY <カラム名> LIMIT <件数>;
UPDATE counter SET count = count + 1 ORDER BY id LIMIT 3; UPDATE user SET score = 0, flag = true WHERE flag = false ORDER BY id LIMIT 2;
さらに、ランダムに選択されたレコードを更新したい場合には以下のように書くことができる。
UPDATE counter SET count = count + 1 ORDER BY rand() LIMIT 3; UPDATE user SET score = 0, flag = true WHERE flag = false ORDER BY rand() LIMIT 2;
ただし、これらのUPDATE文にORDER や LIMIT を付ける方法は、PostgreSQLではサポートされていないことに注意する必要がある。
ちなみに、以下のようにUPDATEとSELECTを組み合わせることでどちらでも使えるSQLが書けそうだが、これはエラーが表示される。
UPDATE counter SET count = count + 1 WHERE id in (SELECT id FROM counter ORDER BY rand() LIMIT 3);
このSQLの問題は2つあり、1つ目はこれから更新するテーブルとサブクエリ内のFROMで同じテーブルを指定することが、MySQLではできないという点だ。
You can't specify target table 'counter' for update in FROM clause
そして、2つ目はINを使ったサブクエリ内でのLIMITは現在のMySQL(ver5.1)ではサポートされていないという点だ。
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
マニュアルを見る限りMySQL6.0でもサポートはされていない。