【MySQL】FIND_IN_SET()を使ってカスタム順序でORDER BYソートする方法
はじめに
MySQLでは、通常のORDER BY句は数値や文字列の昇順・降順でソートしますが、特定の値を優先した独自の順序(カスタム順序)で並べ替えたいケースがあります。例えば、ユーザーのステータスを「BLOCKED → AT WORK → OFFLINE → BUSY」のように任意の順番で表示したい場合です。
このようなカスタムフィールド値での並べ替えを実現するには、FIND_IN_SET()関数を使用します。本記事では、実際にテーブルを作成しながら、その使い方をわかりやすく解説します。
サンプルテーブルの作成
まず、デモ用のテーブルを作成しましょう。以下のSQLでは、ユーザーIDとユーザーステータスを持つテーブル「DemoTable677」を定義しています。
mysql> create table DemoTable677(
UserId int NOT NULL AUTO_INCREMENT PRIMARY KEY,
UserStatus text
);
Query OK, 0 rows affected (1.07 sec)
テストデータの挿入
次に、INSERTコマンドを使っていくつかのレコードを追加します。ステータスには「BUSY」「AT WORK」「OFFLINE」「BLOCKED」の4種類を登録します。
mysql> insert into DemoTable677(UserStatus) values('BUSY');
Query OK, 1 row affected (0.23 sec)
mysql> insert into DemoTable677(UserStatus) values('AT WORK');
Query OK, 1 row affected (0.17 sec)
mysql> insert into DemoTable677(UserStatus) values('OFFLINE');
Query OK, 1 row affected (0.18 sec)
mysql> insert into DemoTable677(UserStatus) values('BLOCKED');
Query OK, 1 row affected (0.17 sec)
登録データの確認
SELECT文ですべてのレコードを表示してみましょう。
mysql> select *from DemoTable677;
実行結果は以下の通りです。
+--------+------------+
| UserId | UserStatus |
+--------+------------+
| 1 | BUSY |
| 2 | AT WORK |
| 3 | OFFLINE |
| 4 | BLOCKED |
+--------+------------+
4 rows in set (0.00 sec)
現時点では、挿入した順番どおりにレコードが並んでいます。
FIND_IN_SET()でカスタム順序に並べ替える
ここからが本題です。FIND_IN_SET()関数をORDER BY句と組み合わせることで、指定した値リストの順序に従ってソートできます。
FIND_IN_SET(検索対象の列, '値1,値2,値3,...') の形式で記述すると、各レコードが値リスト内の何番目に位置するかを数値として返し、その数値を基準に並べ替えが行われます。
以下のクエリでは、「BLOCKED」を先頭に、「AT WORK」「OFFLINE」「BUSY」の順で表示するよう指定しています。
mysql> select *from DemoTable677
ORDER BY FIND_IN_SET(UserStatus, 'BLOCKED,AT WORK,OFFLINE,BUSY');
実行結果:
+--------+------------+
| UserId | UserStatus |
+--------+------------+
| 4 | BLOCKED |
| 2 | AT WORK |
| 3 | OFFLINE |
| 1 | BUSY |
+--------+------------+
4 rows in set (0.03 sec)
ご覧のとおり、リストで指定した順序どおりにレコードが並び替えられました。「BLOCKED」が最初に、「BUSY」が最後に表示されています。
FIND_IN_SET()の仕組みと注意点
仕組み
FIND_IN_SET()は、第2引数の文字列リスト(カンマ区切り)の中から第1引数の値を探し、見つかった位置(1始まりのインデックス)を返します。ORDER BY句内で使うことで、その位置情報をもとにソートが実現します。
- 「BLOCKED」→ リスト内の位置 1
- 「AT WORK」→ リスト内の位置 2
- 「OFFLINE」→ リスト内の位置 3
- 「BUSY」→ リスト内の位置 4
注意点
- リスト外の値の扱い: 第2引数のリストに含まれない値は 0 を返すため、それらのレコードはリスト内の値より先頭に表示されます。意図しない順序になる場合は、条件分岐や追加のソートキーを検討しましょう。
- NULLの扱い: 対象の列がNULLの場合、FIND_IN_SET()はNULLを返します。
- パフォーマンス: 大量データに対してFIND_IN_SET()によるソートを行うと、インデックスを利用できず処理が遅くなる可能性があります。大規模なテーブルでは、ENUM型への変更やCASE式、別途ソート用の順序列を持たせる方法も検討するとよいでしょう。
まとめ
MySQLで独自の順序(カスタム順序)に従ってレコードを並べ替えたい場合は、ORDER BY句とFIND_IN_SET()関数を組み合わせるのが手軽で効果的です。ステータス管理や優先度表示など、実務でもよく使われるテクニックなので、ぜひ覚えておきましょう。データ量が多い場合はパフォーマンス面にも配慮し、適切な設計を選択してください。
-
MySQL:ORDER BY FIELDとOR条件を組み合わせた優先順位付き並べ替えの方法
MySQLでは、ORDER BY句とFIELD()関数を組み合わせることで、特定の値を優先的に並べ替えることができます。本記事では、WHERE句のOR条件とFIELD()関数を併用する方法を、実際のサンプルコードとともにわかりやすく解説します。 サンプルテーブルの作成 まず、動作確認用のテーブルを作成しましょう。 mysql> create table DemoTable1884 ( Marks int ); Query OK, 0 rows
-
MySQLでGROUP BYのように特定の1行だけ更新する方法|ORDER BYとLIMITを活用したUPDATE文の書き方
MySQLでは、UPDATE文の中でGROUP BYを直接使用することができません。しかし、「同じ値を持つ複数のレコードの中から、最初の1行だけを更新したい」というケースは実際の開発でよく発生します。 そんなときに役立つのが、ORDER BYとLIMITを組み合わせたUPDATE文です。この記事では、サンプルテーブルを使いながら、その具体的な手順をわかりやすく解説します。 1. サンプルテーブルを作成する まず、従業員情報を格納するテーブル「DemoTable2018」を作成します。テーブルには、自動採番される主キー「EmployeeId」、従業員名「EmployeeName」、給与「Emp