MySQLでグループごとにランダムな順序で並べ替える方法
MySQLでデータを取得する際、「同じ値を持つレコード同士はまとめたいが、グループ全体の並び順は毎回ランダムにしたい」という要件が出てくることがあります。単純に ORDER BY RAND() を使うと行単位でバラバラになってしまうため、サブクエリとJOINを組み合わせるのがポイントです。この記事では、その具体的な手順をサンプルコード付きで解説します。
1. サンプルテーブルを作成する
まず、動作確認用のテーブルを作成しましょう。
mysql> create table DemoTable ( Id int NOT NULL AUTO_INCREMENT PRIMARY KEY, Value char(1) ); Query OK, 0 rows affected (0.66 sec)
2. レコードを挿入する
insertコマンドを使って、テーブルにいくつかのレコードを追加します。
mysql> insert into DemoTable(Value) values('X');
Query OK, 1 row affected (0.20 sec)
mysql> insert into DemoTable(Value) values('Y');
Query OK, 1 row affected (0.09 sec)
mysql> insert into DemoTable(Value) values('X');
Query OK, 1 row affected (0.30 sec)
mysql> insert into DemoTable(Value) values('X');
Query OK, 1 row affected (0.07 sec)
mysql> insert into DemoTable(Value) values('Y');
Query OK, 1 row affected (0.17 sec)
mysql> insert into DemoTable(Value) values('Z');
Query OK, 1 row affected (0.13 sec)
mysql> insert into DemoTable(Value) values('Z');
Query OK, 1 row affected (0.11 sec)
3. 登録されたレコードを確認する
select文で、テーブル内のすべてのレコードを表示してみます。
mysql> select *from DemoTable;
実行すると、次のような結果が得られます。
+----+-------+ | Id | Value | +----+-------+ | 1 | X | | 2 | Y | | 3 | X | | 4 | X | | 5 | Y | | 6 | Z | | 7 | Z | +----+-------+ 7 rows in set (0.00 sec)
4. グループ単位でランダムに並べ替えるクエリ
ケース1: グループ化したままランダムな順序で表示するには、以下のクエリを実行します。
mysql> select DemoTable.* from DemoTable join ( select Value, rand() as `random_Value` from DemoTable group by Value ) tbl2 on DemoTable.Value = tbl2.Value order by tbl2.`random_Value`;
実行すると、次のような出力になります。
+----+-------+ | Id | Value | +----+-------+ | 6 | Z | | 7 | Z | | 1 | X | | 3 | X | | 4 | X | | 2 | Y | | 5 | Y | +----+-------+ 7 rows in set (0.00 sec)
このクエリの仕組みを見てみましょう。サブクエリ内では GROUP BY Value によって値ごとに1行にまとめられ、そのタイミングで rand() が評価されるため、同じValueを持つグループには共通の乱数値が割り当てられます。元のテーブルをその乱数値とJOINし、乱数値で並べ替えることで、同じグループの行は必ず隣接したまま、グループの並び順だけがランダムになります。
5. 実行のたびに結果が変わることを確認する
ケース2: ランダムな順序で表示しているため、同じクエリでも実行するたびに結果が変わります。もう一度同じクエリを実行してみましょう。
mysql> select DemoTable.* from DemoTable join ( select Value, rand() as `random_Value` from DemoTable group by Value ) tbl2 on DemoTable.Value = tbl2.Value order by tbl2.`random_Value`;
実行結果は次のようになりました。先ほどとはグループの並び順が入れ替わり、各グループ(Y・Z・X)内の行はまとまったまま維持されているのが分かります。
+----+-------+ | Id | Value | +----+-------+ | 2 | Y | | 5 | Y | | 6 | Z | | 7 | Z | | 1 | X | | 3 | X | | 4 | X | +----+-------+ 7 rows in set (0.00 sec)
まとめ
グループ単位のランダムソートを実現するポイントは、「グループごとに一度だけ生成した乱数値を行に付与し、その値で並べ替える」ことです。これにより、行単位ではなくグループ単位のシャッフルが可能になります。ニュース記事のカテゴリ表示や商品一覧など、「カテゴリの順序は変えたいが、同じカテゴリの項目は離したくない」といった場面でぜひ活用してください。
-
MySQLのGROUP BY句で各グループから1行だけを選択・抽出する方法
MySQLでは、GROUP BY句とサブクエリを組み合わせることで、各グループから特定の1行(たとえば最小のIDを持つ行)を取り出すことができます。本記事では、学生の点数データを例に、テーブル作成から実際のクエリ実行までの手順をわかりやすく解説します。 1. テーブルの作成 まず、以下のCREATE TABLE文でサンプル用のテーブルを作成します。 mysql> create table DemoTable1572 -> ( -> StudentId int, &nb
-
MySQLで特定の値を検索してNULLに置き換える方法をわかりやすく解説
MySQLで値を検索してNULLに置き換える基本構文 MySQLでテーブル内の特定の値を見つけてNULLに置き換えたい場合は、UPDATE文とSET句を使って yourColumnName = NULL のように指定します。基本的な構文は以下の通りです。 update yourTableName set yourColumnName=NULL where yourColumnName=yourValue; WHERE句で対象となる値を指定することで、該当する行だけをNULLに更新できるのがポイントです。 サンプルテーブルの作成 まずは動作確認用のテーブルを作成しましょう。 mysql>