みんなが頭を悩ます「ORDER BY句」の問題
まずは、データ最新の書式や研修の表示順について、確認しましょう。ORDER BY句を指定しない場合の表示順は、何順ですか? 「Oracleがデータを取り出した順」ですよね。だから、どんな順に出てくるか、保証されるものではありません。だから、ORDER BY句をつけて、昇順(小さい順)、降順(大きい順)に並べ替えて表示するのですよね。
それでは、昇順に並べた場合、NULLは先頭に表示されますか? 最後ですか? 降順に並べた場合は?
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr;
EMPNO ENAME MGR
---------- ---------- ----------
7934 MILLER 7782
7782 CLARK 7839
7839 KING
例1が示すとおり、昇順に並べた場合、NULLは最後(降順に並べた場合は先頭) に表示されます。 しかし、Oracleの仕様がそうであったとしても、みなさんの業務においては、昇順だろうが降順だろうが、NULLを常に先頭に表示したいという要望があるかもしれません。さあ、そういう場合は、どうすればよいのでしょうか。
問1
上司(mgr)が設定されていない従業員を常にリストの先頭に出力する必要があります。どのSQL文を使用しますか。3つ選びなさい。
-
a. SELECT empno,ename,mgr
FROM emp
WHERE deptno = 10
ORDER BY mgr DESC; -
b. SELECT empno,ename,mgr
FROM emp
WHERE deptno = 10<br/ ORDER BY mgr NULLS FIRST; -
c. SELECT empno,ename,mgr
FROM emp
WHERE deptno = 10
ORDER BY mgr DESC NULLS FIRST; -
d. SELECT empno,ename,mgr
FROM emp<br/ WHERE deptno = 10
ORDER BY mgr DESC NULLS REVERSE; -
e. SELECT empno,ename,mgr
FROM emp
WHERE deptno = 10
ORDER BY mgr ASC NULLS LAST;
正解は、次の実行例のとおり、a、b、cです。
SQL> -- a
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr DESC;
EMPNO ENAME MGR
---------- ---------- ----------
7839 KING
7782 CLARK 7839
7934 MILLER 7782
SQL> -- b
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr NULLS FIRST;
EMPNO ENAME MGR
---------- ---------- ----------
7839 KING
7934 MILLER 7782
7782 CLARK 7839
SQL> -- c
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr DESC NULLS FIRST;
EMPNO ENAME MGR
---------- ---------- ----------
7839 KING
7782 CLARK 7839
7934 MILLER 7782
SQL> -- d
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr DESC NULLS REVERSE;
ORDER BY mgr DESC NULLS REVERSE
*
行4でエラーが発生しました。:
ORA-00905: キーワードがありません。
SQL> -- e
SQL> SELECT empno,ename,mgr
2 FROM emp
3 WHERE deptno = 10
4 ORDER BY mgr ASC NULLS LAST;
EMPNO ENAME MGR
---------- ---------- ----------
7934 MILLER 7782
7782 CLARK 7839
7839 KING
ORDER BY句には、もう1つ便利な機能があります。 指定した件数分表示する機能です。
問2
emp表の中で給与が高い順に表示します。ただし、表示する行は3件のみとします。 どのSQL文を使用しますか。
-
a. SELECT ename,sal FROM emp
WHERE ROWNUM <= 3
ORDER BY sal DESC; -
b. SELECT ename,sal FROM emp
ORDER BY sal DESC FETCH FIRST 3 ROWS ONLY; -
c. SELECT ename,sal FROM emp
ORDER BY sal DESC FETCH FIRST 3 ROWS WITH TIES; -
d.SELECT ename,sal FROM emp
ORDER BY sal ASC FETCH LAST 3 ROWS ONLY;
正解は、次の実行例のとおり、bです。
SQL> -- a
SQL> SELECT ename,sal FROM emp
2 WHERE ROWNUM <= 3
3 ORDER BY sal DESC;
ENAME SAL
---------- ----------
ALLEN 1600
WARD 1250
SMITH 800
SQL> -- b
SQL> SELECT ename,sal FROM emp
2 ORDER BY sal DESC FETCH FIRST 3 ROWS ONLY;
ENAME SAL
---------- ----------
KING 5000
MILLER 4900
SCOTT 3000
SQL> -- c
SQL> SELECT ename,sal FROM emp
2 ORDER BY sal DESC FETCH FIRST 3 ROWS WITH TIES;
ENAME SAL
---------- ----------
KING 5000
MILLER 4900
SCOTT 3000
FORD 3000
SQL> -- d
SQL> SELECT ename,sal FROM emp
2 ORDER BY sal ASC FETCH LAST 3 ROWS ONLY;
ORDER BY sal ASC FETCH LAST 3 ROWS ONLY
*
行2でエラーが発生しました。:
ORA-00905: キーワードがありません。
FETCH FIRSTキーワードを使用して、戻される行の数または割合を指定できます。 ただし、FETCH LASTというキーワードは存在しないので、ご注意ください。
件数を表示するときにはROWS、割合のときはPERCENTを使用します。今回は3件と指定があったので、3 ROWSです。10%と指定された場合は、10 PERCENTと書きます。
実行例からわかるように、給与の多い順に並べると3番目の金額は、実は3000なのですが、同じ金額の人が2人います。順位的に表現すると、同額3位ってことですね。
しかし、設問では「3件のみ」と要求されていたので、ONLYを使用します。「行制限している最後の行」と同じ値が連続していて、その行も表示する場合はWITH TIESを使用します。
あ、aを選択したあなた。Oracle経験が長いですね。 OracleがFETCH FIRSTキーワードをサポートするまでは、ROWNUM疑似列を使用して、限定何件を表示するというSQL文を(副問合せなどを駆使して)書くこともありました。私にも経験あります(苦笑)。 しかし、もうそんなことをする必要はないのです。おぼえておきましょうね。
ちなみに、5件スキップして、6件目から3件表示するということができるOFFSETというキーワードもありますから、復習しておいてください。
もし、資格を取得済みの先輩方が、後輩指導のためにと思ってこの連載を読んでくださっているのなら、SQLとはいえ、最新の書籍や研修で知識/技術を身につけるよう指導してあげてください。 今まで苦労していたことが、キーワード1つで簡単にできるようになっているかもしれません。

