Oracle 10g でウィンドウ関数を使って区間毎に集計する [ LAG() 関数と LEAD() 関数 ]


ウィンドウ関数 LAG() と LEAD() で前後の集計値を取得

Oracle データベースはウィンドウ関数をサポートしていて非常に強力な SQL を 簡単に実行することが出来ます。そのウィンドウ関数を使って、サブクエリー等を 使わずに1つ前の行の値を取得してみます。

複雑なクエリーを組めば出来ないこともないですが、慣れればウィンドウ関数のほうが直感的にわかりやすくパフォーマンスも良いです。

ウィンドウ関数を使うには、OVER 句を使うことによってウィンドウ関数として扱われます。ウィンドウ関数は問い合わせ結果に含まれる行だけでなく、それ以上の行にアクセスすることができます。




テストデータの準備

まず人口が多い上位30カ国の順位データを以下のように用意しました。 なお "rank" 列の順位は世界で人口の多いランキング順位を示しています。
SQL> SELECT * FROM population ;

      RANK COUNTRY              REGION               POPULATION
---------- -------------------- -------------------- ----------
         1 China                Asia                 1409517397
         2 India                Asia                 1339180127
         3 United States        Americas              324459463
         4 Indonesia            Asia                  263991379
         5 Brazil               Americas              209288278
         6 Pakistan             Asia                  197015955
         7 Nigeria              Africa                190886311
         8 Bangladesh           Asia                  164669751
         9 Russia               Europe                143989754
        10 Mexico               Americas              129163276
        11 Japan                Asia                  127484450
        12 Ethiopia             Africa                104957438
        13 Philippines          Asia                  104918090
        14 Egypt                Africa                 97553151
        15 Vietnam              Asia                   95540800
        16 Germany              Europe                 82114224
        17 Congo                Africa                 81339988
        18 Iran                 Asia                   81162788
        19 Turkey               Asia                   80745020
        20 Thailand             Asia                   69037513
        21 United Kingdom       Europe                 66181585
        22 France               Europe                 64979548
        23 Italy                Europe                 59359900
        24 Tanzania             Africa                 57310019
        25 South Africa         Africa                 56717156
        26 Myanmar              Asia                   53370609
        27 South Korea          Asia                   50982212
        28 Kenya                Africa                 49699862
        29 Colombia             Americas               49065615
        30 Spain                Europe                 46354321

30 rows selected.

このデータを基に自分より上位にある国の人口を表示する列を追加してみます。 言い換えますと1つ前の行の値を取得して表示してみます。


LAG() 関数を使って前の行の値を取得する

ここで使うのは LAG() 関数 と OVER(ORDER BY) です。まず OVER(ORDER BY population DESC) で人口を降順に並べ替え、次に呼び出される LAG(population) で前の行の人口 (population) の値を取得しています。

以下に SQL と実行結果を記載します。"previous_population" が自分より 上位の人口となります。これを使えば前の行との差異を簡単に求められます。
SQL> 
SELECT
  country,
  region,
  population,
  lag(population) OVER(ORDER BY population DESC) AS previous_population
FROM population
ORDER BY population DESC;

COUNTRY         REGION     POPULATION PREVIOUS_POPULATION
--------------- ---------- ---------- -------------------
China           Asia       1409517397
India           Asia       1339180127          1409517397
United States   Americas    324459463          1339180127
Indonesia       Asia        263991379           324459463
Brazil          Americas    209288278           263991379
Pakistan        Asia        197015955           209288278
Nigeria         Africa      190886311           197015955
Bangladesh      Asia        164669751           190886311
Russia          Europe      143989754           164669751
Mexico          Americas    129163276           143989754
Japan           Asia        127484450           129163276
Ethiopia        Africa      104957438           127484450
Philippines     Asia        104918090           104957438
Egypt           Africa       97553151           104918090
Vietnam         Asia         95540800            97553151
Germany         Europe       82114224            95540800
Congo           Africa       81339988            82114224
Iran            Asia         81162788            81339988
Turkey          Asia         80745020            81162788
Thailand        Asia         69037513            80745020
United Kingdom  Europe       66181585            69037513
France          Europe       64979548            66181585
Italy           Europe       59359900            64979548
Tanzania        Africa       57310019            59359900
South Africa    Africa       56717156            57310019
Myanmar         Asia         53370609            56717156
South Korea     Asia         50982212            53370609
Kenya           Africa       49699862            50982212
Colombia        Americas     49065615            49699862
Spain           Europe       46354321            49065615

30 rows selected.


LEAD() 関数を使って次の行の値を取得する

先の例の LAG() 関数は前の行の値を取得していましたが、LEAD() 関数は次の行の値を取得します。
SQL> 
SELECT
  country,
  region,
  population,
  lead(population) OVER(ORDER BY population DESC) AS next_population
FROM population
ORDER BY population DESC;

COUNTRY         REGION    POPULATION NEXT_POPULATION
--------------- --------- ---------- ---------------
China           Asia      1409517397      1339180127
India           Asia      1339180127       324459463
United States   Americas   324459463       263991379
Indonesia       Asia       263991379       209288278
Brazil          Americas   209288278       197015955
Pakistan        Asia       197015955       190886311
Nigeria         Africa     190886311       164669751
Bangladesh      Asia       164669751       143989754
Russia          Europe     143989754       129163276
Mexico          Americas   129163276       127484450
Japan           Asia       127484450       104957438
Ethiopia        Africa     104957438       104918090
Philippines     Asia       104918090        97553151
Egypt           Africa      97553151        95540800
Vietnam         Asia        95540800        82114224
Germany         Europe      82114224        81339988
Congo           Africa      81339988        81162788
Iran            Asia        81162788        80745020
Turkey          Asia        80745020        69037513
Thailand        Asia        69037513        66181585
United Kingdom  Europe      66181585        64979548
France          Europe      64979548        59359900
Italy           Europe      59359900        57310019
Tanzania        Africa      57310019        56717156
South Africa    Africa      56717156        53370609
Myanmar         Asia        53370609        50982212
South Korea     Asia        50982212        49699862
Kenya           Africa      49699862        49065615
Colombia        Americas    49065615        46354321
Spain           Europe      46354321

30 rows selected.

上記結果からも分かる通り、次の行の人口(population)が取得できています。 この結果を利用して簡単に次の行との差異を求められます。

このようにウィンドウ関数を使用すると非常に簡単に集計後のデータの前後の値を取得することが可能です。