MySQLのorder byで詳細に条件を指定して並べ替えたい場合。

仕事中で詰まったので調べた。結構、ありがちな処理なんだけど初めて知ったので、情報共有のためにエントリーにしておく。
MySQLで出力される結果を並び替える場合は「order by」を使うんだけど、これはascとdescで昇順と降順の並び替えしかできない。
例えば、給料の日割りと額で並び替えたいって場合は条件を複数並べればいい。
| No | 日割り | 金額 |
|---|---|---|
| 1 | 月給 | 180000 |
| 2 | 時給 | 850 |
| 3 | 日給 | 8000 |
| 4 | 月給 | 150000 |
上記のテーブルがあるときならば下記になる。
select * from 給与明細
order by 日割り desc, 金額 desc;
| No | 日割り | 金額 |
|---|---|---|
| 1 | 月給 | 180000 |
| 4 | 月給 | 150000 |
| 3 | 日給 | 8000 |
| 2 | 時給 | 850 |
ちなみにorder byはint型のような数値にかぎらずvarchar型でもソートできる。日本語でも大丈夫。詳細はこちらでも参照してください。
で、本題なんだけど上記のテーブルで日割りをソートするときに、必ず日給を一番上に来るようにソートするにはどうすれば良いと思う?これ、結構悩んで詰まった。
こういう場合はCase文を使えば良いんである。
CASE WHEN 条件1 THEN 処理 WHEN 条件2 THEN 処理 WHEN 条件3 THEN 処理 … ELSE 処理 END
select * from 給与明細
order by case
when (日割り = '日給') then 100
else 0 end desc, 日割り desc, 金額 desc;
| No | 日割り | 金額 |
|---|---|---|
| 3 | 日給 | 8000 |
| 1 | 月給 | 180000 |
| 4 | 月給 | 150000 |
| 2 | 時給 | 850 |
このSQL文では最初に日割りで日給に当てはまる行に100というパラメータを割り振ってそれ以外には0を割り振る。そしてorder byで並び替えた上で、他の行の並び替えをしている。order byにCase文を使うと条件を指定した柔軟な並び替えが可能になる。
Case文は他にもいろんなことに使える。例えば、県コードは、1:北海道、2:青森、・・・・・・ 47:沖縄というように振られているが、これを東北、関東、九州といった地方単位にまとめて、その単位で人口を集計したい、という場合。
通常ならば新しく地方コードのカラムを追加しなければならないんだけど、テーブルが冗長になる。これをSQL側で対応することができる。
SELECT SUM(popularity),
CASE pre_name
WHEN '徳島県' THEN '四国'
WHEN '香川県' THEN '四国'
WHEN '愛媛県' THEN '四国'
WHEN '高知県' THEN '四国'
WHEN '福岡県' THEN '九州'
WHEN '佐賀県' THEN '九州'
WHEN '長崎県' THEN '九州'
WHEN '熊本県' THEN '九州'
WHEN '大分県' THEN '九州'
ELSE 'その他' END
FROM Table_A
GROUP BY CASE pre_name
WHEN '徳島県' THEN '四国'
WHEN '香川県' THEN '四国'
WHEN '愛媛県' THEN '四国'
WHEN '高知県' THEN '四国'
WHEN '福岡県' THEN '九州'
WHEN '佐賀県' THEN '九州'
WHEN '長崎県' THEN '九州'
WHEN '熊本県' THEN '九州'
WHEN '大分県' THEN '九州'
ELSE 'その他' END;
データの複雑な並び替えや変更を行わないといけないけど、データベースの構造には触れたくないシーンはありがちだ。そういう時にはCase文を使えばなんとかなるかもしれない。
PDOでutf8なのに文字化けした。 - 超メモ帳(Web式)@復活 The used SELECT statements have a different number of columns - 超メモ帳(Web式)@復活 MySQLのバックアップとレストア - 超メモ帳(Web式)@復活