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でもサポートはされていない。