SQL

SQLクエリ結果のパーソナライズ方法: 並べ替え

SQL(Structured Query Language)はデータベースの操作やクエリの実行に使用される強力な言語です。SQLを使用すると、データベースから情報を取得し、結果を表示することができます。しかし、デフォルトの表示形式では、結果が見づらくなる場合があります。この記事では、SQLクエリの結果を見やすくカスタマイズする方法について解説します。

クエリ結果を指定の順序で返す

問題

部署10の従業員の名前、職種、給与を従業員の給与順で(低い方から高い方へ)表示したい。

解決案

ORDER BY句を使います。

select 
  ename,job,sal
from emp
 where deptno = 10
 order by sal asc;

解説

ORDER BY句を使うと、結果セットの行を並べ替えることができます。上の解決策では、行をSALの昇順でソートしています。ORDER BYはデフォルトで昇順にソートするので、ASC句は省略できます。また、DESCを指定すると降順にソートされます。

select ename,job,sal
  from emp
 where deptno = 10
 order by sal desc;

ソートする列名を指定する代わりに、その列を表す番号を指定することもできます。この番号は1から始まり、SELECTリストを左から右へカウントした項目の順番に該当します。

select ename,job,sal
  from emp
 where deptno = 10
 order by 1 desc;

この例のORDER BY句の番号1は、SELECTリストの1番目の列であるenameに該当します。

複数のフィールドでソートする

問題

EMPからの行をまずはDEPTNOで昇順にソートし、その後に給与の降順にソートしたい。

解決案

ORDER BY句で異なるソート列をカンマで区切って指定します。

select empno,deptno,sal,ename,job
  from emp
 order by deptno, sal desc;

解説

ORDER BY内での優先順位は左から右の順になります。SELECTリスト内の列の数値で表した位置を使って順序付けしている場合は、その数値はSELECTリスト内の項目数を超えてはいけません。一般に、SELECTリストにない列で順序付けできますが、そうするには列の名前を明示的に指定する必要があります。しかし、クエリでGROUP BYやDISTINCTを使用している場合、SELECTリストにない列で順序付けすることはできません

部分文字列でソートする

問題

文字列の特定の部分におけるクエリ結果をソートしたい。例えば、EMPテーブルから従業員の名前と職種を取得し、JOBフィールドの最後の2文字でソートしたい。つまり、次のような結果セットを得たい。

解決案

ORDER BY句の中でSUBSTR関数を使います。

select ename,job
  from emp
 order by substr(job,length(job)-1);

解説

部分文字列関数(SUBSTR関数)を使うと、文字列の任意の部分で簡単にソートできます。文字列の最後の2文字でソートするには、文字列の最後(文字列の長さ)を見つけ出し、1を引きます。すると、開始位置は文字列の最後から2番目になります。そして、この開始位置以降のすべての文字列を取得します。

ソート時にNULLを扱う

問題

EMPからの結果をCOMMでソートしたいが、このフィールドはNULLを許容する。
NULLを末尾にソートするか、あるいはNULLを先頭にするかを指定する方法でソートしたい。

解決案

データをどのように表示したいかや、NULLをどのようにソートするかによって、NULLを許容する列を昇順や降順にソートできます。

select ename,sal,comm
  from emp
 order by 3;

select ename,sal,comm
  from emp
 order by 3 desc;

ここでは、NULLを許容する列に非NULLが含まれている場合に、希望に応じて非NULLを昇順または降順にソートします。このような結果を想定している場合もあれば、そうでない場合もあります。非NULLとは異なる方法でNULLをソートしたい場合には、CASE式を使って列を条件付きでソートできます。

CASE式を使って、値がNULLのときに「フラグ」を立てます。この方法では2つの値を持つフラグを使います。1つはNULLを表し、もう1つは非NULLを表します。このフラグを設定すれば、このフラグ列をORDER BY句に追加するだけです。これで非NULLのソートを妨げずに、NULLを最初にするか最後にするかを簡単に制御できます。

-- 非NULLのCOMMを昇順にソート、NULLはすべて末尾
select ename,sal,comm
  from (
select ename,sal,comm,
       case when comm is null then 0 else 1 end as is_null
  from emp
        ) x
  order by is_null desc,comm;
-- 非NULLのCOMMを降順にソート、NULLはすべて末尾
select ename,sal,comm
  from (
select ename,sal,comm,
        case when comm is null then 0 else 1 end as is_null
  from emp
        ) x
 order by is_null desc,comm desc;
-- 非NULLのCOMMを昇順にソート、NULLはすべて先頭 
select ename,sal,comm
  from (
select ename,sal,comm,
       case when comm is null then 0 else 1 end as is_null
  from emp
       ) x
 order by is_null,comm;
-- 非NULLのCOMMを降順にソート、NULLはすべて先頭 
select ename,sal,comm
  from (
select ename,sal,comm,
       case when comm is null then 0 else 1 end as is_null
  from emp
       ) x
 order by is_null,comm desc;

Oracleでは、ここで記載したコードを使う方法以外に、以下のOracle専用の関数を使用して結果を簡単に解決する方法があります。
ORDER BY句に拡張機能NULLS FIRSTNULLS LASTを使って、非NULLがどのようにソートされているかにかかわらずNULLを最初または最後にソートすることができます。

select ename,sal,comm
  from emp
 order by comm nulls last;

解説

補助的な列が必要になります。この補助的な列の目的は、NULLを識別し、NULLをまとめて最初や最後にソートできるようにすることです。次のクエリは、インラインビューXの結果セットを返します。

select ename,sal,comm,
       case when comm is null then 0 else 1 end as is_null
  from emp;

IS_NULLが返す値を使うと、COMMのソートを妨害することなくNULLを最初や最後に簡単にソートできます。

データ依存のキーに対してソートする

問題

条件ロジックに基づいてソートしたい。例えば、JOBがSALESMANならCOMMでソートし、それ以外はSALでソートしたい。

解決案

ORDER BY句内でCASE式を使います。

select ename,sal,job,comm
  from emp
 order by case when job = 'SALESMAN' then comm else sal end;

解説

CASE式を使って、結果のソート方法を動的に変更できます。ORDER BYに渡される値は次のようになります。

select ename,sal,job,comm,
       case when job = 'SALESMAN' then comm else sal end as ordered
  from emp
 order by 5;

まとめ

クエリ結果のソートは主要スキルの1つです。ORDER BY句はとても強力ですが、効果的に使うにはやはり細かな知識が必要なことが少なくありません。

ORDER BY句を使用して特定のカラムを基準に結果を昇順または降順でソートします。これにより、データの整理と分析が容易になります。

ただ、ORDER BY句はとても高度なソートを行えるのに、補助的な機能として解説が疎かになっているサイトがとても多いです。

この記事を読んで、ORDER BY句でここまで出来るのかと思ってもらえると幸いです。