副問合せの基本事項
次に、副問合せに関して「できること/できないこと」を思い出してもらいましょう。
問2
次の中で実行時にエラーになるSQLはどれですか
-
a. SELECT ename,grade FROM emp
JOIN salgrade
ON (SELECT MAX(sal) FROM emp) BETWEEN losal AND hisal
AND sal BETWEEN losal AND hisal; -
b. SELECT department_id,last_name FROM employees
WHERE salary IN (SELECT MAX(salary) FROM employees
GROUP BY department_id); -
c. SELECT department_id,last_name FROM employees
WHERE salary IN (SELECT salary FROM employees
ORDER BY department_id); -
d. SELECT last_name,salary FROM employees
WHERE (department_id,employee_id) IN
(SELECT department_id,employee_id FROM departments); -
e. SELECT department_name FROM departments
WHERE department_id = (SELECT department_id FROM employees
WHERE salary >= (SELECT AVG(salary) FROM employees));
「副問合せに関して正しい記述はどれですか」という設問の選択肢に、「ORDER BY
を含めることができる」や「GROUP BY
を含めることができる」が含まれている場合があります。今回の問題は、その選択肢がSQLになっているバージョンだと思ってください。つまり、要約すると、各選択肢は次を尋ねているのです。
- 選択肢a「比較演算子のどちら側にでも記述できる?」
- 選択肢b「GROUP BYを含めることができる?」
- 選択肢c「ORDER BYを含めることができる?」
- 選択肢d「2つの列を返すことができる?」
- 選択肢e「2つ以上のネストができる?」
一般的に、比較演算子の右側に副問合せを記述することが多いのですが、左側に記述しても構いません。次のとおり、選択肢aは実行時エラーにはなりません(選択肢aは正解)。
SQL> -- 選択肢a SQL> SELECT ename,grade FROM emp 2 JOIN salgrade 3 ON (SELECT MAX(sal) FROM emp) BETWEEN losal AND hisal 4 AND sal BETWEEN losal AND hisal; ENAME GRADE ---------- ---------- KING 5
副問合せにGROUP BY
を含めることもできます(選択肢bは正解)。
SQL> -- 選択肢b SQL> SELECT department_id,last_name FROM employees 2 WHERE salary IN (SELECT MAX(salary) FROM employees 3 GROUP BY department_id); DEPARTMENT_ID LAST_NAME ------------- --------------- 90 King 60 Hunold (途中省略) 70 Baer 110 Higgins 24行が選択されました。
一方、ORDER BY
を含めることはできません(選択肢cは不正解)。
SQL> -- 選択肢c SQL> SELECT department_id,last_name FROM employees 2 WHERE salary IN (SELECT salary FROM employees 3 ORDER BY department_id); ORDER BY department_id) * 行3でエラーが発生しました。: ORA-00907: 右カッコがありません。
そもそも、副問合せでORDER BY
しても、結果には何の影響も与えません。全く無駄な処理です。指定しなくてもいいではなく、指定してはいけないと覚えましょう。
選択肢dは、先に実行結果を見てみましょう。実行例から分かるとおり、2つの列を返すことができます。これが複数列副問合せです。このとき、比較する複数の列は括弧()
で囲むことを忘れないでください(選択肢dは正解)。
SQL> -- 選択肢d SQL> SELECT last_name,salary FROM employees 2 WHERE (department_id,employee_id) IN 3 (SELECT department_id,employee_id FROM departments); LAST_NAME SALARY --------------- ---------- King 24000 Kochhar 17000 (途中省略) Gietz 8300 Allen 107行が選択されました。
選択肢eは、「2つ以上のネストができるか」の確認と同時に「2件以上返ってくる場合は、=
(イコール)ではなく、IN
演算子を使用する」ことを理解できているかも尋ねています。
まず、2つ以上のネストはできます。2件(2行)以上戻すことも可能です。ただし、副問合せから2件以上のレコードが戻ってくる場合には、主問合せの比較演算子は=
ではなくIN
を使用しなければいけません。したがって、選択肢eは次のとおり実行時にエラーになるので不正解です。
SQL> -- 選択肢e SQL> SELECT department_name FROM departments 2 WHERE department_id = (SELECT department_id FROM employees 3 WHERE salary >= (SELECT AVG(salary) FROM employees)); WHERE department_id = (SELECT department_id FROM employees * 行2でエラーが発生しました。: ORA-01427: 単一行副問合せにより2つ以上の行が戻されます