MySQL道普請便り

第147回 ORDER BYを使用してみる

この記事を読むのに必要な時間:およそ 2.5 分

クエリの実行結果を取得する際に,順序を指定して並べ替えをしたい時に,ORDER BYを利用することになると思います。

ORDER BYの最適化処理に関しては,第111回 MySQLのソート処理についてで,MySQLのORDER BYに関する最適化に関して説明されています。パフォーマンスに興味のある方は,そちらをご覧になってください。

今回はORDER BY句の使用方法に関して説明していきます。

検証環境

今回は,第125回 phpMyAdminでDockerで建てたMySQLにアクセスするで記載したdocker-composeを利用して作成します。手元で簡単に試せるように,GitHubのわたしのレポジトリにサンプルコードとして置いてあるので,気軽に試したい方はgit cloneして試してみてください。試すにはdockerとdocker-composeが必要です。

ORDER BYを使用してみる

ここから,ORDER BY句に指定できる値と,それぞれの使用方法について紹介していきます。ORDER BY句に指定できる値は,以下の3種類になります。

  • カラム名
  • ポジション

次に,それぞれの使用法と結果に関して紹介してきいます。

ORDER BY句にカラム名を指定して使用する

この方法は,ORDER BY句を利用する時によく見る使い方だと思います。

以下のクエリは,検証環境にあるzipcodeテーブルで,ORDER BY句にzip_code順に指定して取得するクエリです。ORDER BYの結果としてはASC(昇順), DESC(降順)をつけてないので,今回はデフォルトのASCの動作になります。

SELECT zip_code FROM zipcode ORDER BY zip_code limit 10;

実行すると,以下のような結果が帰ってきます。

+----------+
| zip_code |
+----------+
| 0010000  |
| 0010010  |
| 0010011  |
| 0010012  |
| 0010013  |
| 0010014  |
| 0010015  |
| 0010016  |
| 0010017  |
| 0010018  |
+----------+
10 rows in set (0.30 sec)

結果から,郵便番号が小さい順から順番にソートされていることがわかります。

ORDER BYは複数のカラムを同時に指定することもできます。old_zipcodeとzip_codeでソートするときを考えてみます。両方とも昇順に並び替えると,結果がちょっとわかりにくいので,old_zipcodeは降順に,zip_codeは昇順に並び替えを行ってみます。

SELECT old_zipcode, zip_code FROM zipcode ORDER BY old_zipcode DESC, zip_code limit 10;

結果は以下のようになります。

mysql> SELECT old_zipcode, zip_code FROM zipcode ORDER BY old_zipcode DESC, zip_code limit 10;
+-------------+----------+
| old_zipcode | zip_code |
+-------------+----------+
| 99985       | 9998521  |
| 99985       | 9998522  |
| 99985       | 9998523  |
| 99985       | 9998524  |
| 99985       | 9998525  |
| 99985       | 9998531  |
| 99984       | 9998421  |
| 99984       | 9998422  |
| 99984       | 9998423  |
| 99984       | 9998431  |
+-------------+----------+
10 rows in set (0.17 sec)

old_zipcdeで降順にソートされ,続いてzip_codeのカラムによって昇順にソートされていることがわかります。

ORDER BY句にポジションを使用する

ORDER BY句には,SELECT文で指定したカラムのポジションを指定することで,どのカラムの順序でソートするかを指定することができます。先ほど試したzip_codeのカラムの順序でソートするクエリは,以下のように書くこともできます。

SELECT zip_code FROM zipcode  ORDER BY 1 limit 10;

結果は以下のようになります。

+----------+
| zip_code |
+----------+
| 0010000  |
| 0010010  |
| 0010011  |
| 0010012  |
| 0010013  |
| 0010014  |
| 0010015  |
| 0010016  |
| 0010017  |
| 0010018  |
+----------+
10 rows in set (0.15 sec)

このようにカラムのポジションを指定することでもソートすることができます。このポジションを表す数字は,左から順に1からスタートします。

複数のカラムで順序をソートする場合も,同様に以下のように書けます。

SELECT old_zipcode, zip_code FROM zipcode ORDER BY 1 DESC, 2 limit 10;

上記の結果は以下のようになります。

mysql> SELECT old_zipcode, zip_code FROM zipcode ORDER BY 1 DESC, 2 limit 10;
+-------------+----------+
| old_zipcode | zip_code |
+-------------+----------+
| 99985       | 9998521  |
| 99985       | 9998522  |
| 99985       | 9998523  |
| 99985       | 9998524  |
| 99985       | 9998525  |
| 99985       | 9998531  |
| 99984       | 9998421  |
| 99984       | 9998422  |
| 99984       | 9998423  |
| 99984       | 9998431  |
+-------------+----------+
10 rows in set (0.15 sec)

こちらORDER BY句にカラム名を指定したときのものと同じ結果になっていることがわかります。

このように,カラムのポジションを指定することでもソートすることができます。ただし,可読性が良くないため,パット見た時にどのカラムでソートされているのかがわかりにくいため,調査用にアドホックにクエリを実行する場合などに利用を限定したほうが良いでしょう。

カラムのポジションを間違えた場合や,末尾以外に取得するカラムを増やした場合に,予期せぬソートになってしまうことがあるので注意しましょう。

ORDER BY句に式を使用する

ORDER BY句には式を利用することもできます。zipcodeテーブルを例に考えると47都道府県のデータが入っていますが,特定の県を上に表示したい場合があります。

たとえば東京都を上に表示したい場合に,以下のようなクエリが書けます。

SELECT prefecture FROM zipcode GROUP BY prefecture ORDER BY CASE prefecture WHEN '東京都' THEN 1 ELSE 2 END limit 1;

上記を実行すると以下のようになります。

mysql>  SELECT prefecture FROM zipcode GROUP BY prefecture ORDER BY CASE prefecture WHEN '東京都' THEN 1 ELSE 2 END limit 1;
+------------+
| prefecture |
+------------+
| 東京都     |
+------------+

このように,ORDER BY句には式を入れて使用することができます。並び順をどうしても変更したい場合に使用できますが,indexが使用できないため,非常に重い処理となります。そのため使用する際には,パフォーマンスに注意して利用する必要があります。

まとめ

今回はちょっと特殊なORDER BY句の使用方法も含めて紹介しました。これらのORDER BY句の処理に関して詳しく正確に知りたい方は,公式のリファレンスマニュアルの13.2.10 SELECT ステートメントに説明がありますので,ぜひご一読ください。

今回紹介したとおり,ORDER BY句にはカラム以外にポジションと式を使用することができます。ポジションを使用することは非推奨となっていますが,既存のコードにすでにある場合やライブラリが出力した時に見ることもあると思います。式を利用する場合は,少し複雑なソートをしたい場合などに便利です。ORDER BY句にそれらを利用する場合には,要件と合致しているか考えて利用しましょう。

著者プロフィール

木村浩一郎(きむらこういちろう)

株式会社オプティム 技術統括本部のエンジニア。最近はミドルウェア・インフラ周りのことも少しずつ学習しています。趣味は将棋。好きな戦法は四間飛車。

Twitter:@kk2170