SQLでデータを抽出する際、「別のテーブルにある値を1つだけ持ってきたい」「集計結果と比較してフィルタリングしたい」と悩むことはありませんか?
スカラー副問い合わせ(Scalar Subquery)は、SQL内で「1行1列」の値を返すサブクエリを使用し、定数や列のように扱う強力なテクニックです。
本記事では、Oracle Database 19c を前提に、スカラー副問い合わせの基本構文から、実務で役立つパフォーマンス(高速化)のポイントまで、初心者にも分かりやすく解説します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
結論・スカラー副問い合わせの要点リスト
時間がない方向けに、この機能の特性と注意点をまとめました。
- 戻り値の鉄則: 必ず「1行かつ1列」の結果を返す必要がある(0行の場合は
NULLになる)。 - 配置場所:
SELECT句、WHERE句、ORDER BY句、CASE式の中などで利用可能。 - 動作イメージ: ループ処理のように、主問い合わせの1行ごとに副問い合わせが実行される(相関副問い合わせの場合)。
- 注意点: 便利だが多用すると遅くなる可能性があるため、実行計画やキャッシュ効果の理解が必要。
1. スカラー副問い合わせとは?
スカラー副問い合わせとは、「単一の値(スカラー値)」を返す副問い合わせのことです。
通常、SELECT 文は表形式(複数行・複数列)の結果を返しますが、スカラー副問い合わせは、あたかも「数値の 100」や「文字列の ‘東京’」と同じように、SQLの一部として埋め込むことができます。
どのような場面で使うか
- マスタ参照: 結合(JOIN)を書かずに、コード値に対応する名称を別のテーブルから取得する。
- 集計比較: 「部門ごとの平均給与」など、集計値を条件に使用する。
- ランク計算: 特定の条件を満たす件数を数えて表示する。
2. 基本構文と仕組み
最も一般的な構文は以下の通りです。カッコ ( ) で囲むのがルールです。
SELECT
列A,
(SELECT 対象列 FROM 別テーブル WHERE 条件) AS 別名
FROM
主テーブル;
動作のフロー
- 主テーブルから1行読み込む。
- その行の値を使って、副問い合わせ(カッコの中)を実行する。
- 副問い合わせの結果(1つだけ)を、主問い合わせの結果列として表示する。
- 次の行へ進み、繰り返す。
3. 実践:スカラー副問い合わせの実行例
実際に動くSQLで確認してみましょう。ここでは従業員(Employees)と部門(Departments)のテーブルを使用します。
前提:テーブル作成とデータ準備
まずは環境を作成します。
-- 既存テーブルがある場合は削除(エラー無視)
-- DROP TABLE employees PURGE;
-- DROP TABLE departments PURGE;
-- 部門テーブル
CREATE TABLE departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(50)
);
-- 従業員テーブル
CREATE TABLE employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(50),
dept_id NUMBER,
salary NUMBER
);
-- データ登録
INSERT INTO departments VALUES (1, 'Sales');
INSERT INTO departments VALUES (2, 'Dev');
INSERT INTO employees VALUES (1, 'Tanaka Taro', 1, 300000);
INSERT INTO employees VALUES (2, 'Yamada Hanako', 1, 350000);
INSERT INTO employees VALUES (3, 'Sato Jiro', 2, 400000);
INSERT INTO employees VALUES (4, 'Suzuki Ichiro', 2, 450000);
COMMIT;
SQL> SELECT * FROM departments;
DEPT_ID DEPT_NAME
---------- --------------------
1 Sales
2 Dev
SQL> SELECT * FROM employees;
EMP_ID EMP_NAME DEPT_ID SALARY
---------- -------------------- ---------- ----------
1 Tanaka Taro 1 300000
2 Yamada Hanako 1 350000
3 Sato Jiro 2 400000
4 Suzuki Ichiro 2 450000
ケース1:他テーブルの値を「列」として取得する(SELECT句)
JOIN を使用せずに、従業員一覧に「部門名」を表示します。
SELECT
e.emp_name,
e.salary,
-- ここがスカラー副問い合わせ
(SELECT d.dept_name
FROM departments d
WHERE d.dept_id = e.dept_id) AS dept_name
FROM
employees e;
実行結果:
SQL> SELECT
2 e.emp_name,
3 e.salary,
4 (SELECT d.dept_name
5 FROM departments d
6 WHERE d.dept_id = e.dept_id) AS dept_name
7 FROM
8 employees e;
EMP_NAME SALARY DEPT_NAME
-------------------- ---------- --------------------
Tanaka Taro 300000 Sales
Yamada Hanako 350000 Sales
Sato Jiro 400000 Dev
Suzuki Ichiro 450000 Dev
解説:
e.dept_id(主問い合わせの値)を副問い合わせ内で使用しています(これを「相関」と呼びます)。部門テーブルに該当するIDがない場合、結果は NULL になります。これは LEFT OUTER JOIN と似た挙動です。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
ケース2:集計値と比較してフィルタリングする(WHERE句)
「所属部門の平均給与」よりも高い給与をもらっている社員を探します。
SELECT
e1.emp_name,
e1.salary
FROM
employees e1
WHERE
e1.salary > (
-- 部門ごとの平均給与を計算して返す
SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.dept_id = e1.dept_id
);
実行結果:
SQL> SELECT
2 e1.emp_name,
3 e1.salary
4 FROM
5 employees e1
6 WHERE
7 e1.salary > (
8 SELECT AVG(e2.salary)
9 FROM employees e2
10 WHERE e2.dept_id = e1.dept_id
11 );
EMP_NAME SALARY
-------------------- ----------
Yamada Hanako 350000
Suzuki Ichiro 450000
解説:
各社員の行ごとに、「その社員が所属する部門の平均」を計算し、比較を行っています。
(Sales部の平均: 325,000 / Dev部の平均: 425,000)
4. トラブルシューティング(よくあるエラー)
スカラー副問い合わせを使用する際、頻出するエラーとその対処法です。
| エラーコード | エラーメッセージ | 原因と対処 |
| ORA-01427 | 単一行副問合せにより2つ以上の行が戻されます | 原因: 副問い合わせの結果が2件以上ヒットしています。 対処: 結合条件を見直すか、 ROWNUM = 1 や MAX() 等で1件に絞ってください。 |
| ORA-00936 | 式がありません | 原因: カッコ内の SELECT 句に列が指定されていない、またはカンマの誤記など。対処: 構文を確認してください。 |
| (結果不正) | 意図せず NULL が返る | 原因: 副問い合わせの条件に合致するデータが副側に存在しない(0件)。 対処: NVL( (副問合せ), 0 ) のように、NULL時のデフォルト値を設定します。 |
5. 運用・監視・パフォーマンス上の注意点
スカラー副問い合わせは便利ですが、プロの現場では「パフォーマンス」に細心の注意を払う必要があります。
メリット
- SQLが直感的に読める(結合の記述が複雑にならない)。
GROUP BYを主問い合わせで行わずに、個別の集計値を付与できる。
デメリット・落とし穴
- N+1問題に近い挙動: 行数分だけ副問い合わせが実行される可能性があるため、主テーブルが数百万行あると激しく遅延します。
- コンテキストスイッチ: SQLエンジン内でコンテキストの切り替えが発生し、オーバーヘッドになる場合があります。
高速化のヒント(Oracleの機能)
Oracle Databaseには「スカラー副問い合わせのキャッシュ機能」があります。
入力値(相関条件の値)が同じであれば、過去の実行結果をメモリ上のハッシュテーブルから再利用します。
- 効果的: 部門IDの種類が少ない(例: 10種類)が、従業員は多い(例: 1万人)場合。キャッシュヒット率が高まり高速です。
- 非効果的: 相関条件の値がほぼユニーク(全件バラバラ)な場合。キャッシュが効かず、全件都度実行となり非常に遅くなります。この場合は
LEFT JOINへの書き換えを検討してください。
6. FAQ:よくある質問
Q1. 副問い合わせの結果が0件だった場合、エラーになりますか?
A. いいえ、エラーにはなりません。
スカラー副問い合わせの結果が0行の場合、Oracleは NULL を返します。NVL 関数などで NULL を 0 や ‘-‘ に変換することをお勧めします。
Q2. スカラー副問い合わせと通常の結合(JOIN)、どちらが良いですか?
A. 取得する列数とデータ量によります。
- 1列だけ参照したい、かつデータの種類(カーディナリティ)が少ない場合:スカラー副問い合わせが手軽で高速な場合があります。
- 複数列参照したい、またはデータ量が膨大な場合:通常の
LEFT JOINの方が効率的です。
Q3. SELECT句以外でも使えますか?
A. はい。
SET 句(UPDATE文)、VALUES 句(INSERT文)、ORDER BY 句などで使用可能です。特に ORDER BY (副問い合わせ) は、マスタテーブルの「表示順カラム」でソートしたい場合に便利です。
7. まとめ
スカラー副問い合わせは、SQLの表現力を広げる重要なテクニックです。
- 1行1列を返すのが絶対条件(複数行返ると ORA-01427)。
- SELECT句やWHERE句で、動的な値取得や条件設定に使える。
- キャッシュ機能が効く場合は高速だが、ユニークな値が多い場合はJOINを検討する。
- 結果がない場合は NULL になる点に注意して実装する。
まずは小さなデータセットで挙動を確認し、実行計画を見ながら適切な場面で活用してみてください。
本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。
[参考]
Oracle Database SQL言語リファレンス 19c
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?




コメント