4. Range 3 Preceding
最後は、Range 3 Preceding
なcount(*)
とmin
とmax
とsum
を代用してみます。サンプルを見てみましょう。
sortKey | Val |
1 | 1 |
3 | 4 |
5 | 5 |
7 | 9 |
8 | 8 |
9 | 2 |
10 | 0 |
12 | 5 |
13 | 7 |
14 | 3 |
15 | 5 |
18 | 6 |
select sortKey,Val, count(*) over(order by sortKey Range 3 Preceding) as cnt, min(Val) over(order by sortKey Range 3 Preceding) as minVal, max(Val) over(order by sortKey Range 3 Preceding) as maxVal, sum(Val) over(order by sortKey Range 3 Preceding) as sumVal from OracleCompOlap order by sortKey;
sortKey | Val | cnt | minVal | maxVal | sumVal |
1 | 1 | 1 | 1 | 1 | 1 |
3 | 4 | 2 | 1 | 4 | 5 |
5 | 5 | 2 | 4 | 5 | 9 |
7 | 9 | 2 | 5 | 9 | 14 |
8 | 8 | 3 | 5 | 9 | 22 |
9 | 2 | 3 | 2 | 9 | 19 |
10 | 0 | 4 | 0 | 9 | 19 |
12 | 5 | 3 | 0 | 5 | 7 |
13 | 7 | 3 | 0 | 7 | 12 |
14 | 3 | 3 | 3 | 7 | 15 |
15 | 5 | 4 | 3 | 7 | 20 |
18 | 6 | 2 | 5 | 6 | 11 |
分析関数のRows
指定は、Lag
関数やLead
関数を使って数行前や数行後の行の値を取得して模倣することができました。分析関数のRange
指定は、下記のように相関サブクエリや自己結合を使って模倣できます。なお、array_agg
関数は、集約の内訳を表示するのに便利なので使用してます。
select sortKey,Val, (select count(*) from OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey) as cnt, (select min(b.Val) from OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey) as minVal, (select max(b.Val) from OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey) as maxVal, (select sum(b.Val) from OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey) as sumVal, (select array_agg(b.Val) from OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey) as Vals from OracleCompOlap a order by sortKey;
sortKey | Val | cnt | minVal | maxVal | sumVal | Vals |
1 | 1 | 1 | 1 | 1 | 1 | {1} |
3 | 4 | 2 | 1 | 4 | 5 | {1,4} |
5 | 5 | 2 | 4 | 5 | 9 | {4,5} |
7 | 9 | 2 | 5 | 9 | 14 | {5,9} |
8 | 8 | 3 | 5 | 9 | 22 | {5,9,8} |
9 | 2 | 3 | 2 | 9 | 19 | {9,8,2} |
10 | 0 | 4 | 0 | 9 | 19 | {9,8,2,0} |
12 | 5 | 3 | 0 | 5 | 7 | {2,0,5} |
13 | 7 | 3 | 0 | 7 | 12 | {0,5,7} |
14 | 3 | 3 | 3 | 7 | 15 | {5,7,3} |
15 | 5 | 4 | 3 | 7 | 20 | {5,7,3,5} |
18 | 6 | 2 | 5 | 6 | 11 | {5,6} |
select a.sortKey,a.Val, count(*) as cnt,min(b.Val) as minVal, max(b.Val) as maxVal,sum(b.Val) as sumVal, array_agg(b.Val) as Vals from OracleCompOlap a,OracleCompOlap b where b.sortKey between a.sortKey-3 and a.sortKey group by a.sortKey,a.Val order by a.sortKey;
SQLのイメージは下記となります。order by sortKey Range 3 Preceding
に対応する黄緑線と青線を引いてます。
データ構造によっては、下記のように、Lag
関数やLead
関数を何度も使ってwindow
関数の集約対象になる可能性のある行の値を全て取得してから、case
式でwindow
関数の集約対象かを判断し、count
関数ならばcase
式を、min
関数ならばLeast
関数を、max
関数ならばGreatest
関数を、sum
関数ならばcoalesce
関数を使う。といった手段でも分析関数のRange
指定を模倣できます。
select sortKey,Val, 1+case when Lag1 is null then 0 else 1 end +case when Lag2 is null then 0 else 1 end +case when Lag3 is null then 0 else 1 end as cnt, Least(Val,Lag1,Lag2,Lag3) as minVal, Greatest(Val,Lag1,Lag2,Lag3) as maxVal, Val+coalesce(Lag1,0) +coalesce(Lag2,0) +coalesce(Lag3,0) as sumVal from (select sortKey,Val, case when sortKey1 between sortKey-3 and sortKey then Lag1 end as Lag1, case when sortKey2 between sortKey-3 and sortKey then Lag2 end as Lag2, case when sortKey3 between sortKey-3 and sortKey then Lag3 end as Lag3 from (select sortKey,Val, Lag(sortKey,1) over(order by sortKey) as sortKey1, Lag(sortKey,2) over(order by sortKey) as sortKey2, Lag(sortKey,3) over(order by sortKey) as sortKey3, Lag(Val,1) over(order by sortKey) as Lag1, Lag(Val,2) over(order by sortKey) as Lag2, Lag(Val,3) over(order by sortKey) as Lag3 from OracleCompOlap) a) a;
最後に
本稿では、PostgreSQL 8.4でOracleの分析関数のRows
指定やRange
指定と同じ結果を取得するSQLを扱いました。次回は、array_agg
関数の使用例を扱います。
参考資料
- 9.19. ウィンドウ関数
PostgreSQLのマニュアルです。ウィンドウ関数に関する説明です。