SQLのランダム関数の使い方についてまとめています。


SQLでランダムを使ったサンプルコード集
以下は、MySQLでのサンプルコードです。MySQLのサンプルデータベースEmployeesを使用しています。
SQLでランダムな数(乱数)を取得する
乱数はrand()で取得可能です。0.0~1.0の間の乱数を取得可能です。整数の乱数を取得するには、floor(切り捨て)関数を組み合わせます。
例えば、5以上20以下の乱数を取得するには、floor(5+rand()*15)と記述します。
- mysql> select rand();
- +---------------------+
- | rand() |
- +---------------------+
- | 0.06205727631417781 |
- +---------------------+
- 1 row in set (0.00 sec)
- mysql> select floor(5 + RAND() * 15);
- +------------------------+
- | floor(5 + RAND() * 15) |
- +------------------------+
- | 8 |
- +------------------------+
- 1 row in set (0.00 sec)
- mysql> select floor(5 + RAND() * 15);
- +------------------------+
- | floor(5 + RAND() * 15) |
- +------------------------+
- | 17 |
- +------------------------+
- 1 row in set (0.00 sec)
- mysql> select floor(5 + RAND() * 15);
- +------------------------+
- | floor(5 + RAND() * 15) |
- +------------------------+
- | 12 |
- +------------------------+
- 1 row in set (0.00 sec)
SQLでランダムな値を テーブルに挿入する
テーブルの値に乱数を挿入することも可能です。以下のサンプルは、同じinsert文ですが、実行するたびに異なる値がテーブルに挿入されます。
- mysql> create table employees.randomtable ( r int not null );
- Query OK, 0 rows affected (0.12 sec)
- mysql> insert into randomtable ( r ) values ( floor(5 + RAND() * 15) );
- Query OK, 1 row affected (0.01 sec)
- mysql> insert into randomtable ( r ) values ( floor(5 + RAND() * 15) );
- Query OK, 1 row affected (0.01 sec)
- mysql> insert into randomtable ( r ) values ( floor(5 + RAND() * 15) );
- Query OK, 1 row affected (0.01 sec)
- mysql> select * from randomtable;
- +----+
- | r |
- +----+
- | 7 |
- | 16 |
- | 9 |
- +----+
- 3 rows in set (0.00 sec)
SQLでランダムな順番で レコードを取り出す
下記のサンプルは、対象テーブルからランダムな順番で10件のデータを取り出すサンプルです。
ただし、テーブル全体に対して乱数でソートをかけるため、クエリが非常に重くなるので注意が必要。以下のケースでは、10件の取得に3.07秒かかっています。
explainで実行計画をチェックすると、テーブル全体(約28万件)に対してインデックスなしのテーブルフルスキャンを実行していることがわかります。
【関連記事】
▶SQLのexplainは、実行計画を表示 遅いSQLのボトルネックを発見する
件数の少ないテーブルに対しては、有効な方法と言えるでしょう。
- select *
- from salaries
- order by Rand()
- limit 10;
- +--------+--------+------------+------------+
- | emp_no | salary | from_date | to_date |
- +--------+--------+------------+------------+
- | 453998 | 49498 | 1988-05-23 | 1988-06-29 |
- | 269607 | 65039 | 2002-06-08 | 9999-01-01 |
- | 85666 | 80434 | 1994-01-14 | 1995-01-14 |
- | 464086 | 62364 | 1999-11-26 | 2000-11-25 |
- | 441784 | 59685 | 1997-06-26 | 1998-06-26 |
- | 470206 | 80771 | 1999-05-31 | 2000-05-30 |
- | 234186 | 65600 | 2001-03-29 | 2002-03-29 |
- | 451094 | 54430 | 1995-02-10 | 1996-02-10 |
- | 454337 | 50130 | 1994-10-31 | 1995-10-31 |
- | 89644 | 57349 | 1992-07-28 | 1993-07-28 |
- +--------+--------+------------+------------+
- 10 rows in set (3.07 sec)
- mysql> explain select * from salaries order by Rand() limit 10;
- +----+-------------+----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
- | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
- +----+-------------+----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
- | 1 | SIMPLE | salaries | NULL | ALL | NULL | NULL | NULL | NULL | 2838426 | 100.00 | Using temporary; Using filesort |
- +----+-------------+----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
- 1 row in set, 1 warning (0.02 sec)
【関連記事】
▶SQL limitを使ったページング、ランダム抽出、速度改善をおこなう
まとめ

- 乱数はrand()関数で取得可能
- 整数の乱数を取得するにはfloor関数を組み合わせる
- テーブルからランダム順にレコード取得する際は、テーブル件数に注意