3. 中央値(メジアン)を求める
今度は中央値(メジアン)を求めます。『HAVING句の力』で提示されている以下のSQLを、window
関数を使って書き換えてみます。
SELECT AVG(DISTINCT income) FROM (SELECT T1.income FROM Graduates T1, Graduates T2 GROUP BY T1.income --S1の条件 HAVING SUM(CASE WHEN T2.income >= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2.0 --S2の条件 AND SUM(CASE WHEN T2.income <= T1.income THEN 1 ELSE 0 END) >= COUNT(*) / 2.0 ) a;
まずは、データの具体的な例を挙げて考えます。なお、incomeの順位を持つRn列も付与して考えます。
case1 case2 income Rn income Rn ------- -- ------- -- 10,000 1 10,000 1 10,000 2 10,000 2 10,000 3 10,000 3 15,000 4 15,000 4 15,000 5 15,000 5 20,000 6 20,000 7 20,000 8 30,000 9 400,000 10
case1が、データ件数が偶数の場合で、中央値は、(15000+20000) / 2 = 17500
です。case2が、データ件数が奇数の場合で、中央値は、10000
です。
まとめると、データ件数が偶数なら、(データ件数 / 2)
番目と(データ件数 / 2 +1)
番目の、平均が中央値です。データ件数が奇数なら、(データ件数 / 2 + 0.5)
番目が中央値ですので、答えは、下記となります。
select avg(income) from (select income, Row_Number() over(order by income) as Rn, count(*) over() as DataCount from Graduates) a where (mod(DataCount,2) = 0 and Rn in(DataCount/2,DataCount/2+1)) or (mod(DataCount,2) = 1 and Rn = Ceil(DataCount/2.0));
インラインビューの中で、Row_Number
関数で順位、count
関数でデータ件数を求めてます。そして、データ件数が偶数か奇数かでwhere
句の条件を分岐させてます。
なお、PostgreSQLでは、整数同士を/
演算子を使って割り算すると、余りを切り捨ててしまうので、2.0で割ってます。
最後に
本稿では、『分析関数の衝撃1 (前編)』をPostgreSQL 8.4用にリニューアルした内容を扱いました。次回は、『分析関数の衝撃2 (中編)』をPostgreSQL 8.4用にリニューアルした内容を扱います。
参考資料
- 『9.19. ウィンドウ関数』(PostgreSQL 8.4.0文書)
- 『SELECT』(PostgreSQL 8.4.0文書)
- 『9.3. 算術関数と演算子』(PostgreSQL 8.4.0文書)
PostgreSQLのマニュアルです。ウィンドウ関数に関する説明です。
PostgreSQLのマニュアルです。Select文の評価順序について解説されてます。
PostgreSQLのマニュアルです。整数同士を/演算子を使って割り算した時の仕様が解説されてます。