「SQL」カテゴリーアーカイブ

SQL関連のカテゴリ

SQL:結合順序を意識してクエリ最適化を行う方法

SQLでパフォーマンスを高めるうえで「結合順序(Join Order)」は非常に重要な要素です。
同じ結果を返すクエリでも、テーブルの結合順序によって処理時間が大きく変わることがあります。

この記事では、結合順序を意識したSQLの最適化方法を、実例とともにわかりやすく解説します。


🔍 なぜ結合順序が重要なのか

SQLの実行順序は見た目の記述順と異なり、最適化エンジンが最も効率的な順序を自動で選択します。
しかし、結合対象のテーブルサイズや結合条件によっては、自動最適化が必ずしも最適とは限りません

特に以下のようなケースでは、結合順序が大きく影響します。

状況パフォーマンスへの影響
大規模テーブルを先に結合している不要なデータを大量に読み込む可能性
絞り込み条件のないテーブルを先に結合フルスキャンのリスク
結合条件にインデックスが効いていない結合ごとに多重ループが発生

🧩 結合順序の基本原則

一般的に、以下の順序を意識すると効率的です。

  1. データ件数の少ないテーブルから結合する

  2. WHERE句で絞り込めるテーブルを先に結合する

  3. インデックスの効くテーブルを優先する

  4. 結合条件(ON句)は明確に指定する

例1:非効率な結合順序

この場合、employeesが数十万件あり、departmentsが数百件なら、
大テーブル→小テーブルの順になり、効率が悪くなります。


✅ 効率的な結合順序の書き方(例)

例2:効率的な書き方

先にdepartments(小テーブル)を起点にしてemployeesを結合すると、
条件に合う部署のみを先に絞り込めるため、結合コストを大幅に削減できます。


🧮 実行計画で結合順序を確認する

実際に最適化できているかを確認するには、**実行計画(EXPLAIN)**を確認します。

チェックポイント

項目確認ポイント
typeALL(全件走査)よりrefやindexが望ましい
rows結合ごとの推定行数を確認し、不要な膨張がないか
ExtraUsing where, "Using index" など最適化の有無を確認

⚙️ 結合順序の強制指定(ヒント句)

DBによっては**ヒント句(Hint)**を利用して結合順序を指定することも可能です。

Oracle の例

MySQL の例

STRAIGHT_JOINを使うと、記述順通りの結合順序で実行されます。


⚡ 実践Tipsまとめ

最適化ポイント内容
小さいテーブルを先に結合大量データの無駄読みを防ぐ
WHERE句の絞り込みを早期適用不要データを結合前に排除
実行計画を確認JOIN順序やインデックス利用を把握
ヒント句を活用自動最適化がうまく働かない場合に使用

💡 まとめ

  • SQLの結合順序は、パフォーマンスチューニングの重要ポイントです。

  • 自動最適化に頼るだけでなく、結合対象のデータ規模や条件を意識して設計することが大切です。

  • 実行計画やヒント句を活用し、最適なクエリ構造を追求しましょう。

SQL:インデックスヒント(INDEX HINT)でクエリ最適化を行う方法

1. インデックスヒントとは?

SQLの**インデックスヒント(INDEX HINT)**とは、データベースに対して「このテーブルでは特定のインデックスを使用して実行してほしい」と明示的に指示するための構文です。
通常、DBエンジン(オプティマイザ)が自動で最適な実行計画を選びますが、統計情報が古い・複雑な条件句などの場合に誤ったインデックスを選ぶことがあります。

そのようなとき、開発者が明示的にインデックスを指定して最適化を誘導するのがINDEX HINTの目的です。


2. 一般的な書き方

Oracleの場合

MySQLの場合

SQL Serverの場合

データベースヒント指定方法備考
Oracle/*+ INDEX(テーブル名 インデックス名) */ヒント句はコメント形式
MySQLUSE INDEX (インデックス名)FORCE INDEX / IGNORE INDEX も可
SQL ServerWITH (INDEX(インデックス名))テーブルヒントとして指定

3. MySQLにおけるINDEX HINTの種類

種類意味使用例
USE INDEX指定したインデックスを優先的に使用USE INDEX (idx_col1)
FORCE INDEX指定インデックスを強制的に使用FORCE INDEX (idx_col1)
IGNORE INDEX指定インデックスを無視して検索IGNORE INDEX (idx_col1)

4. 実行計画を確認する

インデックスヒントを付与したら、実際に利用されているかを確認することが重要です。

MySQL

Oracle


チェック項目内容
key列(MySQL)使用されたインデックス名
access path(Oracle)INDEX RANGE SCAN などが表示される
実行コストコストが下がっているか確認

5. 使用上の注意点

注意点内容
1. 過信しないヒントは一時的なチューニングであり、将来的な統計情報変化で逆効果になることも。
2. 実行計画を常に確認ヒント適用後は EXPLAIN で確認すること。
3. SQL互換性に注意各DBMSで構文が異なるため、移植性が下がる。
4. ヒント指定よりも統計情報更新が基本統計情報を更新することで自動最適化が正しく働くことも多い。

6. 実用例:複合インデックスを明示的に使用

以下のように複数条件を持つ検索で、DBが誤ったインデックスを選ぶ場合に有効です。

このように、複合インデックスの指定順序に合わせてヒントを指定することで、不要な全件スキャンを防ぐことができます。


7. まとめ

ポイント内容
自動最適化が基本まずはDBエンジンに任せるのが原則
ヒントは最終手段特定クエリで誤選択時のみ使用
EXPLAINで検証効果を数値で確認
統計情報更新も忘れずにオプティマイザの精度を保つために重要

SQL:ウィンドウ関数(OVER句)でランキング・累計を計算する

データ分析やレポート作成では、「順位付け」「累計」 のような集計処理がよく登場します。
従来はサブクエリや自己結合を使う必要がありましたが、SQLの ウィンドウ関数(OVER句) を使えば簡潔に記述できます。
この記事では、代表的な使い方と主要DBMSごとの対応状況をサンプル付きで解説します。


🧠 ウィンドウ関数とは?

ウィンドウ関数とは、集計関数に対して「範囲(ウィンドウ)」を指定できる機能です。
通常の SUM()AVG() はグループ全体を集計しますが、OVER() を使うことで「行単位の集計」も可能になります。

🔸 基本構文

関数名(列名) OVER (PARTITION BY 列名 ORDER BY 列名)
役割
PARTITION BYグループを分ける(省略可)
ORDER BY並び順を指定
ROWS BETWEEN ~範囲を細かく指定(任意)

🏅 ランキングを求める

商品の売上データを例に、売上額で順位をつけます。

📘 サンプルテーブル:sales

productcategoryamount
A飲料300
B飲料500
C食品400
D食品200
E食品700

📗 SQL例

📊 実行結果

categoryproductamountrank
飲料B5001
飲料A3002
食品E7001
食品C4002
食品D2003

ポイント

  • 同じカテゴリ内で順位を付与 (PARTITION BY category)

  • 売上が高い順に並び替え (ORDER BY amount DESC)

  • RANK() は同順位がある場合にスキップ(例:1位,1位,3位)


🔢 累計を求める

カテゴリ別に売上の累計を出してみましょう。

📗 SQL例

📊 結果

categoryproductamountrunning_total
飲料B500500
飲料A300800
食品E700700
食品C4001100
食品D2001300

ポイント

  • SUM()OVER() を組み合わせることで行ごとの累積が可能

  • ORDER BY により順序を指定できる

  • PARTITION BY を省略すると全体累計に


🧮 他の代表的なウィンドウ関数

関数説明
ROW_NUMBER()連番(重複なし)を付与
RANK()同順位があるとスキップ(例:1,1,3)
DENSE_RANK()同順位があっても連続(例:1,1,2)
NTILE(n)n等分にグループ分け(例:四分位)
LAG(col, n)n行前の値を取得
LEAD(col, n)n行後の値を取得
SUM(), AVG(), MAX(), MIN()累計・平均などの集計を行単位で

💡 応用例:前回比を計算する

前回の売上からの増減を求めたい場合は LAG() 関数を使用します。



FROM sales;
categoryproductamountprev_amountdiff
飲料B500NULLNULL
飲料A300500-200
食品E700NULLNULL
食品C400700-300
食品D200400-200

🧭 DBMS別のウィンドウ関数対応表

DBMS対応状況対応バージョン備考
Oracle Database◎ 完全対応8i 以降ウィンドウ関数発祥の実装。機能最も豊富
PostgreSQL◎ 完全対応8.4 以降PARTITION, ORDER, RANGE句など全対応
MySQL○ 部分対応8.0 以降8.0から正式対応(それ以前は非対応)
SQL Server◎ 完全対応2012 以降LAG/LEADなどもサポート
SQLite○ 部分対応3.25 以降一部関数は制限あり(NTILEなど)
MariaDB△ 限定対応10.2 以降SUMなどは対応、LAG/LEADは制限あり
IBM Db2◎ 完全対応9.7 以降分析関数として強力なサポートあり
Snowflake / BigQuery◎ 完全対応最新クラウドDWH系でもネイティブ対応

補足

  • 旧バージョンのMySQL(5.x系)ではウィンドウ関数が非対応のため、サブクエリで代替が必要。

  • PostgreSQLとOracleはROWS BETWEENなどの範囲指定も細かく制御可能。

  • BigQueryはOVER()句のほかQUALIFY句でフィルタリングが可能。


🔍 まとめ

観点内容
機能グループ単位での行ごとの集計・順位付け
主な用途累計・ランキング・前回比・順位比較
メリットサブクエリ不要・可読性向上・パフォーマンス改善
対応DBOracle, PostgreSQL, SQL Server, MySQL 8+, BigQueryなど

ウィンドウ関数は、分析SQLの最重要機能といっても過言ではありません。
集計・比較・順位などを自在に扱えるようになれば、レポート作成の幅が大きく広がります。

SQL:NOT IN と NOT EXISTS の違いとパフォーマンス比較

SQLでサブクエリを使って除外条件を指定する際に利用される「NOT IN」と「NOT EXISTS」。両者の動作の違いやNULLの扱い、パフォーマンス差を実例付きで徹底解説します。

EXISTSANSI SQL(国際標準SQL)に含まれる構文 のため、
ほぼすべてのリレーショナルデータベースで利用できます。
古いバージョンの一部DBを除き、標準構文として移植性が非常に高いのが特徴です。

1. NOT IN と NOT EXISTS の基本構文

構文例説明
NOT INSELECT * FROM A WHERE ID NOT IN (SELECT ID FROM B);サブクエリの結果に含まれないIDを抽出
NOT EXISTSSELECT * FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE A.ID = B.ID);Bに同じIDが存在しない場合のみAを取得

ポイント:

  • 両者とも「除外」目的だが、評価タイミングとNULL処理が異なる。


2. 動作の違い(NULLの扱いに注目)

条件NOT INの結果NOT EXISTSの結果
サブクエリにNULLが含まれるすべての行が除外される正常に比較できる
サブクエリが空(0件)全件取得される全件取得される

理由:
NOT IN は内部的に「A.ID <> B.ID」を繰り返すような処理を行うため、NULLが含まれると比較結果がUNKNOWNとなり、全体が評価されなくなる。
一方、NOT EXISTS行ごとに存在チェックを行うため、NULLの影響を受けない。


3. 実行結果の比較例

以下の例を見てみましょう。

テーブルA

ID NAME
1 田中
2 鈴木
3 佐藤

テーブルB

ID
1
NULL

4. パフォーマンスの違い

比較項目NOT INNOT EXISTS
NULLの影響受ける受けない
実行計画(最適化)インデックス利用されにくい場合あり最適化されやすい
大量データ時の効率遅くなるケースありより安定して高速
Oracleの最適化傾向半結合(Anti-Join)に変換されることあり同様に最適化される

実測例(概略)

件数NOT IN所要時間NOT EXISTS所要時間
1万件0.25秒0.20秒
10万件3.1秒1.8秒

※ 実測環境:Oracle 19c、インデックスあり、CPU 4コア相当


5. どちらを使うべきか

条件推奨句
サブクエリにNULLが含まれる可能性ありNOT EXISTS
データが小規模でNULLなしどちらでも可
大規模データ・実行計画を重視NOT EXISTS(推奨)
可読性を優先NOT EXISTS のほうが誤動作が少ない

6. まとめ

観点内容
ANSI SQL対応○(どのDBでも使用可能)
実行パフォーマンスDBごとに最適化される(MySQL 8以降で特に改善)
推奨度高い(NOT INより安全で移植性が高い)
注意点MySQL 5.x 以前では最適化が弱いケースがある

✔ 結論:
除外条件を指定する場合は、基本的に「NOT EXISTS」を使う方が安全で高速です。
ただし、NULLが確実に存在しないことが保証される小規模データではNOT INも選択肢になります。

SQL便利技:PIVOTとUNPIVOTで自由自在に表を変換する方法

SQLを使ってデータを扱うとき、表の形を「横持ち」や「縦持ち」に変換したい場面は多々あります。
例えば、月ごとの売上を列ごとに並べたい、あるいはアンケート結果を1列にまとめたいなど。

こうした「表の回転」に便利なのが PIVOTUNPIVOT です。
本記事では、それぞれの使い方と、主要なDBMSごとの違いを整理します。


PIVOTとは?

PIVOTは 縦持ちデータを横持ちに変換する 機能です。
例:月ごとの売上を集計して列化する。

サンプルデータ
商品売上
A1月100
A2月150
B1月200
B2月180

PIVOTのイメージ

商品1月売上2月売上
A100150
B200180


UNPIVOTとは?

UNPIVOTは 横持ちデータを縦持ちに変換する 機能です。
例:上記の「商品×月売上表」を再び「商品・月・売上」の縦持ちに戻す。


各DBMSでの書き方比較

1. SQL Server

SQL Serverはネイティブで PIVOT / UNPIVOT をサポート。

 


2. Oracle

Oracleは PIVOT / UNPIVOT が標準で利用可能。


3. PostgreSQL

PostgreSQLはPIVOT句を持たないため、crosstab関数(tablefunc拡張) を使う。

 


4. MySQL

MySQLには PIVOT 句はなく、CASE式 + GROUP BY を使う。

UNPIVOTも標準構文がないので、PostgreSQL同様 UNION ALL を用いる。

 


DBMS比較表

DBMSPIVOT対応UNPIVOT対応代替手段
SQL Serverネイティブネイティブそのまま使用可
Oracleネイティブネイティブそのまま使用可
PostgreSQLなしなしcrosstab関数 / UNION ALL
MySQLなしなしCASE式 + GROUP BY / UNION ALL

 

まとめ

  • SQL Server / Oracle → PIVOT/UNPIVOTがシンプルに使える。

  • PostgreSQL / MySQL → 標準ではなく、関数やCASE式で工夫が必要。

「集計を横に展開したい」あるいは「フラットに戻したい」とき、
DBMSに応じた方法を覚えておくと、データ整形がぐっと楽になります。

DENSE_RANKとRANKの違いを使い分けるランキング便利技

SQLでデータに順位を付けたいとき、よく使われるのが RANKDENSE_RANK です。
どちらもウィンドウ関数として利用でき、同点がある場合にどう順位を振るかが異なります。

「売上ランキングを作りたい」「部門ごとのTOP3を出したい」といった実務シーンでは、両者の違いを理解していないと期待通りの結果にならないことがあります。

本記事では、RANKとDENSE_RANKの基本的な違い を解説したうえで、実務での使い分け方、さらに DBMSごとのサポート状況 までわかりやすく紹介します。


RANKとは?

RANK は、同点がある場合に同じ順位を付けますが、その分次の順位が飛びます。

例:テストの点数ランキング

名前点数RANK
Aさん1001
Bさん952
Cさん952
Dさん904
 

👉 2位が2人いるため、次の順位は「4位」となります。


DENSE_RANKとは?

DENSE_RANK は、同点の場合も同じ順位を付けますが、次の順位は飛ばさずに連続します。

名前点数DENSE_RANK
Aさん1001
Bさん952
Cさん952
Dさん903

 

👉 2位が2人いても、次の順位は「3位」となります。


実務での便利な活用例

1. 売上ランキングを作る

売上データから各商品の順位を求めたいときは DENSE_RANK が便利です。

👉 同順位の商品があっても「順位が飛ばない」ので、一覧が見やすくなります。

2. 部門別ランキングを作る

「部門ごとにランキングを出したい」場合は、PARTITION BY を組み合わせます。

👉 部門ごとに順位がリセットされ、それぞれの中でランキングが作成されます。

3. TOP Nの商品を抽出する

「売上TOP3の商品を取得したい」といった場合は注意が必要です。

👉 RANK を使うと、3位が同点の場合に4件以上取得されることがあります。

DENSE_RANK なら「必ず3位まで」に限定できるため安全です。


DBMSごとの違い

Oracle Database

  • RANK / DENSE_RANK ともに早期からサポート

  • 標準SQLに準拠し、安定して利用可能

PostgreSQL

  • バージョン8.4以降でサポート

  • 標準SQL準拠のため、OracleやSQL Serverとほぼ同じ書き方で利用できる

MySQL

  • MySQL 8.0 以降で利用可能

  • それ以前(5.x系など)では未対応で、ユーザー変数を使った代替実装が必要

SQL Server (Microsoft)

  • 2005以降でサポート

  • 標準SQLと同じ感覚で利用可能

👉 まとめると:

  • Oracle / PostgreSQL / SQL Server → そのまま使える

  • MySQL 8.0以降 → 標準対応

  • MySQL 5.x以前 → 対応なし(代替実装が必要)


まとめ

  • RANK → 同順位があると次の順位が飛ぶ(例:1,2,2,4)

  • DENSE_RANK → 順位が連続(例:1,2,2,3)

  • 実務での使い分け:

    • 売上ランキング → DENSE_RANK

    • 部門別の表彰や順位 → RANK

    • TOP N抽出 → DENSE_RANK が安全

  • DBMSによってサポート状況が異なるため、特にMySQLはバージョンを確認することが重要

SQLでのランキング処理はシーンによって適切に関数を選ぶのがコツです。

正規表現(REGEXP)でSQLがもっと楽になる!実践パターン集

SQLの検索でよく使われる LIKE 句は便利ですが、複雑な条件指定には限界があります。
そこで強力な武器となるのが 正規表現(REGEXP)
この記事では、基本的な使い方からよく使うパターン、さらに「SQLで利用できる正規表現の一覧」をまとめました。


1. REGEXPの基本構文

SQLでは REGEXP を用いて文字列検索を行います。

➡ 名前が Aで始まるユーザー を抽出。

2. 使用できる正規表現の一覧(MySQL準拠)

SQLで使える代表的な正規表現を整理しました。
※DBエンジンにより若干差異あり(MySQL、PostgreSQL、Oracleなど)

パターン意味使用例
^行頭にマッチ^A → Aで始まる
$行末にマッチZ$ → Zで終わる
.任意の1文字c.t → cat, cot, cut
[...]文字クラス[0-9] → 数字1文字
[^...]否定の文字クラス[^0-9] → 数字以外
*0回以上の繰り返しa* → \\" a aaa"
+1回以上の繰り返しa+ → a, aa
?0回または1回colou?r → color, colour
{n}n回の繰り返し[0-9]{4} → 4桁の数字
{n,}n回以上の繰り返し[0-9]{2,} → 2桁以上の数字
{n,m}n〜m回の繰り返し[A-Z]{2,5} → 2〜5文字の大文字
|OR条件cat|dog → cat または dog
()グループ化(abc)+ → abc, abcabc
[:digit:]数字[[:digit:]] → 0〜9
[:alpha:]英字[[:alpha:]] → A〜Z, a〜z
[:alnum:]英数字[[:alnum:]] → 英数字
[:space:]空白文字[[:space:]] → 空白, 改行, タブ
[:upper:]大文字[[:upper:]] → 大文字
[:lower:]小文字[[:lower:]] → 小文字

3. よく使う実践パターン

(1) 先頭・末尾の一致

➡ Pで始まる商品コード。

(2) 日付フォーマット判定

➡ “YYYY-MM-DD” を含むログ。

(3) メールアドレス判定

➡ GmailまたはYahooメール利用者を抽出。

(4) 商品コードの書式検証

アルファベット3文字+数字 の形式に一致。

(5) 拡張子フィルタ

➡ PDFファイルだけを抽出。

4. REGEXPのメリットと注意点

メリット

  • 複雑な条件をシンプルに表現できる

  • SQLの可読性が向上

  • データ品質チェックに有効

注意点

  • DBごとに正規表現エンジンが異なる(MySQL、PostgreSQL、Oracleで互換性に注意)

  • パフォーマンス低下の可能性があるため、大量データ処理時はインデックス設計と併用が望ましい


SQLでのREGEXPサポート比較(DBMSごと)

DBMSREGEXPサポート演算子/関数例備考
MySQLREGEXP, REGEXP_REPLACE8.0以降はICUベース
PostgreSQL~, ~*, !~, !~*高度な正規表現OK
OracleREGEXP_LIKE, REGEXP_SUBSTRPOSIX互換
SQL Server(CLR関数経由)ネイティブ未対応
SQLiteREGEXP(要自作関数)デフォルト非対応
BigQueryREGEXP_CONTAINS などクラウドSQL
SnowflakeRLIKE, REGEXPほぼMySQL互換

 

まとめ

REGEXPを使えばSQLの検索が格段に柔軟になります。
一覧表を参考に、ログ解析やメール判定、コード検証などに応用してみてください。

「LIKEでは表現できない…」と思ったら、REGEXPの出番です!

PL/SQL:BULK COLLECTとFORALLを使った効率的な大量データ処理

Oracle PL/SQLを使って大量データを処理する際、1行ずつループして処理を行うとパフォーマンスが低下します。
このようなケースで活躍するのが BULK COLLECTFORALL です。

これらを活用することで、SQLとPL/SQL間のコンテキスト切り替えを最小限に抑え、大量データを効率的に処理できます。


BULK COLLECTとは?

BULK COLLECTは、複数行のデータを一括でコレクション(配列型変数)に格納する仕組みです。

基本構文

 
SELECT カラム名 BULK COLLECT INTO コレクション変数 FROM テーブル名 WHERE 条件;

使用例

✅ 通常のSELECT INTOでは1行しか取得できませんが、BULK COLLECTを使うと複数行をまとめて変数に格納できます。


FORALLとは?

FORALLは、コレクションに格納されたデータを使って一括処理(INSERT/UPDATE/DELETE)を行う構文です。

基本構文

 
FORALL インデックス IN コレクション.FIRST .. コレクション.LAST DML文;

使用例

FORループで1件ずつUPDATEするよりも大幅に高速化できます。

BULK COLLECTとFORALLを組み合わせる

実務では、BULK COLLECTで一括取得 → FORALLで一括更新/削除といった流れがよく使われます。

処理フロー例

  1. BULK COLLECTで対象データを配列に取得

  2. 配列の内容をFORALLで一括更新

  3. コミット

このように組み合わせることで、バッチ処理や大量データ更新におけるパフォーマンスを劇的に改善できます。


パフォーマンス比較

  • 従来のループ処理
    SQLとPL/SQL間で行き来が多くなり、数万件以上の処理では遅くなる

  • BULK COLLECT + FORALL
    コンテキストスイッチが最小化され、処理速度が数倍〜数十倍向上するケースもある


注意点

  • BULK COLLECTで一度に大量データを取得するとメモリ不足の可能性あり
    LIMIT句を組み合わせて分割取得が推奨

  • FORALLはDML専用(SELECTでは使えない)

  • 例外処理はSAVE EXCEPTIONSを付けて制御することも可能


まとめ

  • BULK COLLECT → 複数行を一括取得

  • FORALL → 複数行を一括処理

  • 大量データ処理では必須テクニック

  • メモリ管理や例外処理に注意しつつ使うと、バッチ処理の効率が大幅に改善


💡 実際のプロジェクトでは「数十万件以上のデータ更新」で特に効果が出やすいため、PL/SQLチューニングの定番として覚えておきましょう。

SQL:サブクエリの使い方を徹底解説!実例で学ぶネストされたSELECT文

はじめに

SQLを学んでいると「サブクエリ(副問い合わせ)」という言葉を耳にすることが多いでしょう。
サブクエリは、SELECT文の中にさらにSELECT文をネスト(入れ子構造)して使う機能です。
複雑な条件指定や集計処理をシンプルに書けるため、業務システムやデータ分析で頻繁に活用されます。

この記事では、サブクエリの基本から実践的な使い方まで、実例を交えて徹底解説します。


サブクエリとは?

**サブクエリ(Subquery)**とは、SQL文の中に埋め込まれるSELECT文のことです。
通常のSQL文の一部として利用され、主に次のような用途があります。

  • WHERE句での条件指定

  • FROM句での仮想テーブル生成

  • SELECT句での派生列計算


サブクエリの基本構文

サブクエリの基本的な形は以下の通りです。

SELECT 列名 FROM テーブル WHERE 条件式 (SELECT 列名 FROM 別テーブル WHERE 条件);
ポイントは、サブクエリの結果が単一値・リスト・テーブルとして返ることです。

用途によって、スカラサブクエリ、行サブクエリ、テーブルサブクエリと呼ばれることもあります。


例1:WHERE句でのサブクエリ

もっともよく使われるのが WHERE句での利用 です。
例えば「平均給与より高い社員を取得する」場合は次のように書けます。

  • サブクエリ (SELECT AVG(給与) FROM 社員) で平均給与を取得

  • メインクエリで給与がそれを上回る社員を抽出


例2:IN句とサブクエリ

複数の値を条件にする場合は IN句 を利用します。

  • サブクエリで特定の日に注文された商品IDを取得

  • メインクエリでその商品情報を表示


例3:FROM句でのサブクエリ(派生テーブル)

FROM句でサブクエリを使えば、仮想テーブルを作成して結合や集計が可能です。

  • サブクエリで部署ごとの平均給与を計算

  • メインクエリで平均給与が30万円を超える部署を抽出


例4:SELECT句でのサブクエリ

SELECT句にサブクエリを埋め込むことで、計算列を動的に追加できます。

 
SELECT 社員名, (SELECT 部署名 FROM 部署 WHERE 部署.部署ID = 社員.部署ID) AS 部署名 FROM 社員;
  • 社員ごとに部署名をサブクエリで取得

  • JOINを使わずにシンプルに表記可能(ただしパフォーマンス注意)


サブクエリを使うときの注意点

  1. パフォーマンスに注意
    ネストが深すぎると処理速度が落ちる場合があります。JOINやCTE(共通テーブル式)で置き換えを検討しましょう。

  2. 返却される値の型に注意
    単一値を期待しているのに複数行が返るとエラーになります。

  3. 読みやすさを意識
    サブクエリは便利ですが、複雑になると可読性が低下します。適切にインデントを整えるのが重要です。

  4. DBMS別:サブクエリ対応表
    DBMSWHERE句でのサブクエリFROM句でのサブクエリSELECT句でのサブクエリ相関サブクエリ備考
    Oracle○ 完全対応○ インラインビュー○ 利用可○ 高性能大規模業務で多用
    MySQL○ (v4.1以降対応)○ 利用可○ 利用可△ パフォーマンス注意古いバージョンでは非対応
    PostgreSQL○ 標準準拠○ 利用可○ 利用可○ 高性能複雑な分析処理に強い
    SQL Server○ 完全対応○ 利用可○ 利用可○ ただし過剰利用注意実行計画が膨らむことあり

まとめ

  • サブクエリはSQL文の中でネストされたSELECT文

  • WHERE、FROM、SELECTなど多くの場面で利用可能

  • 集計や複雑な条件指定をシンプルに書ける

  • パフォーマンスと可読性に注意が必要

サブクエリをマスターすることで、SQLの表現力が大幅に広がります。
まずはシンプルなWHERE句から練習し、徐々に複雑なケースに挑戦してみましょう!

Oracle:DECODE関数とCASE式の違いを徹底解説

Oracle SQLを学んでいると、「DECODE関数」と「CASE式」の使い分けで迷う方は多いのではないでしょうか。
どちらも条件分岐を行うために利用できますが、機能や表現力には明確な違いがあります。

本記事では、DECODEとCASEの特徴、違い、実務での使い分けポイントをわかりやすく解説します。


1. DECODE関数とは?

DECODEOracle独自の関数 で、簡易的な条件分岐を行うために利用されます。
基本構文は次の通りです。

 
DECODE(式, 検索値1, 置換値1, 検索値2, 置換値2, ..., デフォルト値)
  • 指定した式の値と「検索値」が一致すれば、その「置換値」を返す

  • 一致しなければ最後のデフォルト値を返す(省略可能)

例:部署IDに応じて部署名を返す


2. CASE式とは?

CASESQL標準 でサポートされる条件分岐の構文です。
Oracleだけでなく、他のデータベース(MySQL、PostgreSQLなど)でも使えます。

構文(シンプルCASE)

 
CASEWHEN1 THEN 結果1 WHEN2 THEN 結果2 ... ELSE 結果N END

構文(検索CASE)

 
CASE WHEN 条件式1 THEN 結果1 WHEN 条件式2 THEN 結果2 ... ELSE 結果N END

例:部署IDに応じて部署名を返す


3. DECODEとCASEの比較

項目DECODECASE
標準SQLOracle独自機能SQL標準でサポート
構文関数形式式形式
条件「等しい場合」のみ判定可能!ERROR! C4 -> Formula Error: Unexpected ,
可読性ネストが増えると読みにくい複雑な条件もわかりやすく記述可能
移植性Oracleに依存他DBでも利用可能
推奨度古いコードに多い現在はこちらが主流
 

4. 実務での使い分けポイント

  • 既存システムのSQLでDECODEが多用されている → 互換性を保つためそのまま使用するケースあり

  • 新規開発や複雑な条件分岐 → 可読性・移植性を考えて CASE式を推奨

  • DB移行を見据える場合 → CASE式を選択しておくと移植がスムーズ


まとめ

  • DECODE関数:Oracle独自。簡単な条件分岐向け。古いSQLでよく見かける。

  • CASE式:SQL標準。複雑な条件も書けて、移植性・可読性に優れる。

👉 今後の開発では CASE式を優先的に利用 するのがおすすめです。