「SQLite」タグアーカイブ

SQL:中央値(MEDIAN)をSQLで求める方法まとめ

中央値を使う場面

中央値(MEDIAN)は、極端な値(外れ値)の影響を受けにくい指標として、業務システムやデータ分析でよく使われます。
例:処理時間の中央値、売上の中央値、レスポンス時間の中央値など。

SQLではDBMSによって書き方が大きく異なるため、この記事では主要DBMSごとに中央値の求め方をわかりやすく整理します。


1. Oracleで中央値を求める(標準でMEDIAN関数あり)

Oracle Database は最も簡単で、MEDIAN集計関数が標準で使用可能

条件付き

パーティションごと(グループ別)

Oracleユーザーは基本これだけでOKです。


2. PostgreSQLで中央値を求める

PostgreSQL には MEDIAN関数は無い ため、percentile_cont を使います。

グループ別

col がNULLの場合は自動的に除外されます。


3. MySQLで中央値を求める(8.0〜)

MySQLにも MEDIAN関数は無い ため、以下の方法を使います。

方法1:ウィンドウ関数+ROW_NUMBER

奇数なら真ん中の値、偶数なら2つの平均を返します。


4. SQL Serverで中央値を求める

SQL Server も MEDIAN 関数なし。
PERCENTILE_CONT を使うのが最もシンプル。

グループ別

SQL Serverユーザーはこの書き方を覚えておけば十分です。


5. SQLiteで中央値を求める

SQLite はウィンドウ関数が使える(3.25〜)ので MySQLと同じ方法が有効。


6. DBMS別「中央値の求め方」まとめ表

DBMS中央値の関数代表的な書き方
OracleMEDIANSELECT MEDIAN(col)
PostgreSQLpercentile_contpercentile_cont(0.5) WITHIN GROUP
MySQLなし(手動)ウィンドウ関数で行番号+平均
SQL ServerPERCENTILE_CONTPERCENTILE_CONT(0.5)
SQLiteなし(手動)ウィンドウ関数で行番号+平均

外れ値があるデータ分析では平均より中央値の方が実態を正確に示すケースが多いので、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も選択肢になります。