見出し画像

MySQL8.0でウィンドウ関数を理解する

背景

前回の記事に引き続いてMySQLのお勉強中で,ウィンドウ関数が「MySQL徹底入門 第4版 MySQL 8.0対応」が出てきました.
MySQLでは8.0からウィンドウ関数が使えるようになったみたいで,2000年代にサポートされているDBMSもあったようです.

僕がウィンドウ関数を知ったのは「達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ」を読んだ時なのですが,そのときは「ほほ〜ん,そういうのもあるんだね〜」程度しか理解していなかったので,此度は公式ドキュメントなどを読み込んで理解を深めました.

あと,こちらの本にも少し出てきています.

最初に以下の記事を読んで,わかりやすかったので参考になるかもしれません.


※この記事ではMySQL8.0(Docker, tag:8.0)で実行しています


ウィンドウ関数でできること

ウィンドウ関数でできることを確認するために軽く使ってみます.
公式ドキュメントの最初から読んでいこうと思ったのですが,その次のドキュメントのほうがとっつきやすかったので,こちらの上から順になぞっていきます.

公式ドキュメントはデータが入っている前提で話が進んでいくので,自分でテーブルとインサート文を作成します.

# テーブル作成
# 公式ドキュメントの通りだとidはないが一応作っておく
CREATE TABLE sales (
   id INT NOT NULL PRIMARY KEY auto_increment,
   year INT NOT NULL,
   country VARCHAR(30) NOT NULL,
   product VARCHAR(30) NOT NULL,
   profit INT NOT NULL
);

# レコードのインサート
INSERT INTO sales(year, country, product, profit) VALUES
( 2000, 'Finland', 'Computer', 1500),
( 2000, 'Finland', 'Phone', 100),
( 2001, 'Finland', 'Phone', 10),
( 2000, 'India', 'Calculator', 75),
( 2000, 'India', 'Calculator', 75),
( 2000, 'India', 'Computer', 1200),
( 2000, 'USA', 'Calculator', 75),
( 2000, 'USA', 'Computer', 1500),
( 2001, 'USA', 'Calculator', 50),
( 2001, 'USA', 'Computer', 1500),
( 2001, 'USA', 'Computer', 1200),
( 2001, 'USA', 'TV', 150),
( 2001, 'USA', 'TV', 100);

# 確認
SELECT  *
FROM sales
ORDER BY country, year, product;
+----+------+---------+------------+--------+
| id | year | country | product    | profit |
+----+------+---------+------------+--------+
|  1 | 2000 | Finland | Computer   |   1500 |
|  2 | 2000 | Finland | Phone      |    100 |
|  3 | 2001 | Finland | Phone      |     10 |
|  4 | 2000 | India   | Calculator |     75 |
|  5 | 2000 | India   | Calculator |     75 |
|  6 | 2000 | India   | Computer   |   1200 |
|  7 | 2000 | USA     | Calculator |     75 |
|  8 | 2000 | USA     | Computer   |   1500 |
|  9 | 2001 | USA     | Calculator |     50 |
| 10 | 2001 | USA     | Computer   |   1500 |
| 11 | 2001 | USA     | Computer   |   1200 |
| 12 | 2001 | USA     | TV         |    150 |
| 13 | 2001 | USA     | TV         |    100 |
+----+------+---------+------------+--------+

準備ができたので,まずウィンドウ関数を使わない場合の確認からしていきます.

# profitの総数
SELECT SUM(profit) AS total_profit
FROM sales;
+--------------+
| total_profit |
+--------------+
|         7535 |
+--------------+

profitの総数を算出することができました.
次に,最初の確認のSELECT * FROM sales ORDER BY country, year, product; の結果にprofitの総数の列を付け足した結果を得たい場合はどうすればよいでしょうか?

# この結果が得られるSQLを書きたい
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
|  1 | 2000 | Finland | Computer   |   1500 |         7535 |
|  2 | 2000 | Finland | Phone      |    100 |         7535 |
|  3 | 2001 | Finland | Phone      |     10 |         7535 |
|  4 | 2000 | India   | Calculator |     75 |         7535 |
|  5 | 2000 | India   | Calculator |     75 |         7535 |
|  6 | 2000 | India   | Computer   |   1200 |         7535 |
|  7 | 2000 | USA     | Calculator |     75 |         7535 |
|  8 | 2000 | USA     | Computer   |   1500 |         7535 |
|  9 | 2001 | USA     | Calculator |     50 |         7535 |
| 10 | 2001 | USA     | Computer   |   1500 |         7535 |
| 11 | 2001 | USA     | Computer   |   1200 |         7535 |
| 12 | 2001 | USA     | TV         |    150 |         7535 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
+----+------+---------+------------+--------+--------------+​

次のSQLはエラーになってしまいます.

# エラーになる
SELECT *, SUM(profit) AS total_profit
FROM sales;

ここで使えるのがウィンドウ関数です.次のSQLだと期待した結果を得ることができます.OVER()などのウィンドウ関数の構文については後ほど詳しくみますので,一旦スルーします.

SELECT
   *,
   SUM(profit) OVER() AS total_profit
FROM sales
ORDER BY country, year, product;
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
|  1 | 2000 | Finland | Computer   |   1500 |         7535 |
|  2 | 2000 | Finland | Phone      |    100 |         7535 |
|  3 | 2001 | Finland | Phone      |     10 |         7535 |
|  4 | 2000 | India   | Calculator |     75 |         7535 |
|  5 | 2000 | India   | Calculator |     75 |         7535 |
|  6 | 2000 | India   | Computer   |   1200 |         7535 |
|  7 | 2000 | USA     | Calculator |     75 |         7535 |
|  8 | 2000 | USA     | Computer   |   1500 |         7535 |
|  9 | 2001 | USA     | Calculator |     50 |         7535 |
| 10 | 2001 | USA     | Computer   |   1500 |         7535 |
| 11 | 2001 | USA     | Computer   |   1200 |         7535 |
| 12 | 2001 | USA     | TV         |    150 |         7535 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
+----+------+---------+------------+--------+--------------+

他の例をみてみます.
先ほどと同じようにまずはウィンドウ関数を使わずに国ごとのprofitの総数を算出してみます.

# 国ごとのprofitの総数
SELECT country, SUM(profit) AS country_profit
FROM sales
GROUP BY country
ORDER BY country;
+---------+----------------+
| country | country_profit |
+---------+----------------+
| Finland |           1610 |
| India   |           1350 |
| USA     |           4575 |
+---------+----------------+

次に,最初の確認のSELECT * FROM sales ORDER BY country, year, product; の結果に国ごとのprofitの総数の列を付け足した結果を得たい場合はどうすればよいでしょうか?

# この結果が得られるSQLを書きたい
+----+------+---------+------------+--------+----------------+
| id | year | country | product    | profit | country_profit |
+----+------+---------+------------+--------+----------------+
|  1 | 2000 | Finland | Computer   |   1500 |           1610 |
|  2 | 2000 | Finland | Phone      |    100 |           1610 |
|  3 | 2001 | Finland | Phone      |     10 |           1610 |
|  4 | 2000 | India   | Calculator |     75 |           1350 |
|  5 | 2000 | India   | Calculator |     75 |           1350 |
|  6 | 2000 | India   | Computer   |   1200 |           1350 |
|  7 | 2000 | USA     | Calculator |     75 |           4575 |
|  8 | 2000 | USA     | Computer   |   1500 |           4575 |
|  9 | 2001 | USA     | Calculator |     50 |           4575 |
| 10 | 2001 | USA     | Computer   |   1500 |           4575 |
| 11 | 2001 | USA     | Computer   |   1200 |           4575 |
| 12 | 2001 | USA     | TV         |    150 |           4575 |
| 13 | 2001 | USA     | TV         |    100 |           4575 |
+----+------+---------+------------+--------+----------------+

以下のSQLではエラーになってしまいます.

# エラーになる
SELECT *, SUM(profit) AS country_profit
FROM sales
GROUP BY country
ORDER BY country;

ウィンドウ関数を使用すると,(ソートの順が少し異なりますが)期待した結果を得ることができます.

SELECT
   *,
   SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;
+----+------+---------+------------+--------+----------------+
| id | year | country | product    | profit | country_profit |
+----+------+---------+------------+--------+----------------+
|  1 | 2000 | Finland | Computer   |   1500 |           1610 |
|  2 | 2000 | Finland | Phone      |    100 |           1610 |
|  3 | 2001 | Finland | Phone      |     10 |           1610 |
|  4 | 2000 | India   | Calculator |     75 |           1350 |
|  5 | 2000 | India   | Calculator |     75 |           1350 |
|  6 | 2000 | India   | Computer   |   1200 |           1350 |
|  7 | 2000 | USA     | Calculator |     75 |           4575 |
|  8 | 2000 | USA     | Computer   |   1500 |           4575 |
|  9 | 2001 | USA     | Calculator |     50 |           4575 |
| 11 | 2001 | USA     | Computer   |   1200 |           4575 |
| 10 | 2001 | USA     | Computer   |   1500 |           4575 |
| 13 | 2001 | USA     | TV         |    100 |           4575 |
| 12 | 2001 | USA     | TV         |    150 |           4575 |
+----+------+---------+------------+--------+----------------+

このようにウィンドウ関数では行を折りたたまず(1レコードなどに集約されず),結果を出力することができます.


無名ウィンドウ関数と名前つきウィンドウ関数

ウィンドウ関数について深堀りしていきます.
ウィンドウ関数には無名と名前付きの2種類の書き方があります.

一般的には無名ウィンドウ関数のほうが普及しているようです(参照 達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ 2.必ずわかるウィンドウ関数).しかし,初めてウィンドウ関数を学ぶのであれば名前付きのほうが理解しやすいです.
先ほど出てきたSQLは無名ウィンドウ関数です.どちらの同じ結果になります.

# 無名ウィンドウ関数
SELECT
   *,
   SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;

# 名前付きウィンドウ関数
SELECT
  *,
   SUM(profit) OVER w AS country_profit
FROM sales
WINDOW w AS (PARTITION BY country)
ORDER BY country, year, product, profit;

ちょっとハマったのですが,ウィンドウ句( WINDOW w AS ... )はORDER BY句の前に書かないとエラーになります.wは好きな名前をつけることができます.

名前付きウィンドウ関数のメリットは使い回しができる点です.
以下の例では国ごとにレコード数を集約,計算してcountとして結果を出力しています.

SELECT
 *,
  SUM(profit) OVER w AS country_profit,
  COUNT(*) OVER w AS count
FROM sales
WINDOW w AS (PARTITION BY country)
ORDER BY country, year, product, profit;
+----+------+---------+------------+--------+----------------+-------+
| id | year | country | product    | profit | country_profit | count |
+----+------+---------+------------+--------+----------------+-------+
|  1 | 2000 | Finland | Computer   |   1500 |           1610 |     3 |
|  2 | 2000 | Finland | Phone      |    100 |           1610 |     3 |
|  3 | 2001 | Finland | Phone      |     10 |           1610 |     3 |
|  4 | 2000 | India   | Calculator |     75 |           1350 |     3 |
|  5 | 2000 | India   | Calculator |     75 |           1350 |     3 |
|  6 | 2000 | India   | Computer   |   1200 |           1350 |     3 |
|  7 | 2000 | USA     | Calculator |     75 |           4575 |     7 |
|  8 | 2000 | USA     | Computer   |   1500 |           4575 |     7 |
|  9 | 2001 | USA     | Calculator |     50 |           4575 |     7 |
| 11 | 2001 | USA     | Computer   |   1200 |           4575 |     7 |
| 10 | 2001 | USA     | Computer   |   1500 |           4575 |     7 |
| 13 | 2001 | USA     | TV         |    100 |           4575 |     7 |
| 12 | 2001 | USA     | TV         |    150 |           4575 |     7 |
+----+------+---------+------------+--------+----------------+-------+


ウィンドウ関数とは

ざっくりとウィンドウ関数についてみてきましたが,じゃあどの部分がウィンドウ関数なのか?と聞かれると

The OVER clause is permitted for many aggregate functions, which therefore can be used as window or nonwindow functions, depending on whether the OVER clause is present or absent:
(中略)
MySQL also supports nonaggregate functions that are used only as window functions. For these, the OVER clause is mandatory:

とあるので,例えばSUM()は集約関数であることはご存知だと思いますが,OVER句があればSUM()をウィンドウ関数とも呼ぶことができます.OVER句がなければただの集約関数です.

自分はWINDOW w AS ... やOVER(PARTITION BY country) の部分がウィンドウ関数だと思っていたのですが,どうやら違うみたいでした.

# OVER句があればウィンドウ関数として扱える集約関数
AVG()
BIT_AND()
BIT_OR()
BIT_XOR()
COUNT()
JSON_ARRAYAGG()
JSON_OBJECTAGG()
MAX()
MIN()
STDDEV_POP(), STDDEV(), STD()
STDDEV_SAMP()
SUM()
VAR_POP(), VARIANCE()
VAR_SAMP()
# ウィンドウ関数としてのみ使用できる専用関数
CUME_DIST()
DENSE_RANK()
FIRST_VALUE()
LAG()
LAST_VALUE()
LEAD()
NTH_VALUE()
NTILE()
PERCENT_RANK()
RANK()
ROW_NUMBER()


OVER句の中の記述がない場合

まずOVER句に何も記述がない場合です.

SELECT
   *,
   SUM(profit) OVER() AS total_profit
FROM sales
ORDER BY country, year, product;
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
|  1 | 2000 | Finland | Computer   |   1500 |         7535 |
|  2 | 2000 | Finland | Phone      |    100 |         7535 |
|  3 | 2001 | Finland | Phone      |     10 |         7535 |
|  4 | 2000 | India   | Calculator |     75 |         7535 |
|  5 | 2000 | India   | Calculator |     75 |         7535 |
|  6 | 2000 | India   | Computer   |   1200 |         7535 |
|  7 | 2000 | USA     | Calculator |     75 |         7535 |
|  8 | 2000 | USA     | Computer   |   1500 |         7535 |
|  9 | 2001 | USA     | Calculator |     50 |         7535 |
| 10 | 2001 | USA     | Computer   |   1500 |         7535 |
| 11 | 2001 | USA     | Computer   |   1200 |         7535 |
| 12 | 2001 | USA     | TV         |    150 |         7535 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
+----+------+---------+------------+--------+--------------+​

先ほども出てきたSQLですが,OVER句に何も記述がない場合はsalesテーブルの全てのprofitの値を合算した7535になります.


ORDER BY句

次にOVER句でORDER BY句を入れてみます.

SELECT
  *,
   SUM(profit) OVER(ORDER BY id) AS total_profit
FROM sales;
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
|  1 | 2000 | Finland | Computer   |   1500 |         1500 |
|  2 | 2000 | Finland | Phone      |    100 |         1600 |
|  3 | 2001 | Finland | Phone      |     10 |         1610 |
|  4 | 2000 | India   | Calculator |     75 |         1685 |
|  5 | 2000 | India   | Calculator |     75 |         1760 |
|  6 | 2000 | India   | Computer   |   1200 |         2960 |
|  7 | 2000 | USA     | Calculator |     75 |         3035 |
|  8 | 2000 | USA     | Computer   |   1500 |         4535 |
|  9 | 2001 | USA     | Calculator |     50 |         4585 |
| 10 | 2001 | USA     | Computer   |   1500 |         6085 |
| 11 | 2001 | USA     | Computer   |   1200 |         7285 |
| 12 | 2001 | USA     | TV         |    150 |         7435 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
+----+------+---------+------------+--------+--------------+

ORDER BY句で指定すると,idの昇順でレコードを並べて,自分以下のidの合計値がtotal_profitになります.

ちなみにOVER句の中のORDER BY句( ORDER BY id )と外のORDER BY句( ORDER BY product DESC )の内容を一致させる必要はありません.total_profitは自分以下のidの合計値で,レコード全体はproductの降順になっているだけです.

SELECT
  *,
   SUM(profit) OVER(ORDER BY id) AS total_profit
FROM sales
ORDER BY product DESC;
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
| 12 | 2001 | USA     | TV         |    150 |         7435 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
|  2 | 2000 | Finland | Phone      |    100 |         1600 |
|  3 | 2001 | Finland | Phone      |     10 |         1610 |
|  1 | 2000 | Finland | Computer   |   1500 |         1500 |
|  6 | 2000 | India   | Computer   |   1200 |         2960 |
|  8 | 2000 | USA     | Computer   |   1500 |         4535 |
| 10 | 2001 | USA     | Computer   |   1500 |         6085 |
| 11 | 2001 | USA     | Computer   |   1200 |         7285 |
|  4 | 2000 | India   | Calculator |     75 |         1685 |
|  5 | 2000 | India   | Calculator |     75 |         1760 |
|  7 | 2000 | USA     | Calculator |     75 |         3035 |
|  9 | 2001 | USA     | Calculator |     50 |         4585 |
+----+------+---------+------------+--------+--------------+

ORDER BY country, year, product でソートしてみると以下のようにソートの全ての条件が同じ(id = 4, 5など)になってしまうレコードのtotal_profitは同じになります.

SELECT
   *,
   SUM(profit) OVER(ORDER BY country, year, product) AS total_profit
FROM sales;
+----+------+---------+------------+--------+--------------+
| id | year | country | product    | profit | total_profit |
+----+------+---------+------------+--------+--------------+
|  1 | 2000 | Finland | Computer   |   1500 |         1500 |
|  2 | 2000 | Finland | Phone      |    100 |         1600 |
|  3 | 2001 | Finland | Phone      |     10 |         1610 |
|  4 | 2000 | India   | Calculator |     75 |         1760 |
|  5 | 2000 | India   | Calculator |     75 |         1760 |
|  6 | 2000 | India   | Computer   |   1200 |         2960 |
|  7 | 2000 | USA     | Calculator |     75 |         3035 |
|  8 | 2000 | USA     | Computer   |   1500 |         4535 |
|  9 | 2001 | USA     | Calculator |     50 |         4585 |
| 10 | 2001 | USA     | Computer   |   1500 |         7285 |
| 11 | 2001 | USA     | Computer   |   1200 |         7285 |
| 12 | 2001 | USA     | TV         |    150 |         7535 |
| 13 | 2001 | USA     | TV         |    100 |         7535 |
+----+------+---------+------------+--------+--------------+


PARTITION BY

PARTITION BY句はレコードの分割を指定します.
先ほども出てきたSQLですが,PARTITION BY country とするとcountryごとに区切って,その合計値がcountry_profitになります.

SELECT
   *,
   SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;
+----+------+---------+------------+--------+----------------+
| id | year | country | product    | profit | country_profit |
+----+------+---------+------------+--------+----------------+
|  1 | 2000 | Finland | Computer   |   1500 |           1610 |
|  2 | 2000 | Finland | Phone      |    100 |           1610 |
|  3 | 2001 | Finland | Phone      |     10 |           1610 |
|  4 | 2000 | India   | Calculator |     75 |           1350 |
|  5 | 2000 | India   | Calculator |     75 |           1350 |
|  6 | 2000 | India   | Computer   |   1200 |           1350 |
|  7 | 2000 | USA     | Calculator |     75 |           4575 |
|  8 | 2000 | USA     | Computer   |   1500 |           4575 |
|  9 | 2001 | USA     | Calculator |     50 |           4575 |
| 11 | 2001 | USA     | Computer   |   1200 |           4575 |
| 10 | 2001 | USA     | Computer   |   1500 |           4575 |
| 13 | 2001 | USA     | TV         |    100 |           4575 |
| 12 | 2001 | USA     | TV         |    150 |           4575 |
+----+------+---------+------------+--------+----------------+

別の結果もみてみます.PARTITION BY product とするとproductごとに区切った合計値がproduct_profitとなります.わかりやすいようにOVER句の外のORDER BY句もproductを指定していますが,必ずしも揃える必要はありません.

SELECT
  *,
   SUM(profit) OVER(PARTITION BY product) AS product_profit
FROM sales
ORDER BY product;
+----+------+---------+------------+--------+----------------+
| id | year | country | product    | profit | product_profit |
+----+------+---------+------------+--------+----------------+
|  4 | 2000 | India   | Calculator |     75 |            275 |
|  5 | 2000 | India   | Calculator |     75 |            275 |
|  7 | 2000 | USA     | Calculator |     75 |            275 |
|  9 | 2001 | USA     | Calculator |     50 |            275 |
|  1 | 2000 | Finland | Computer   |   1500 |           6900 |
|  6 | 2000 | India   | Computer   |   1200 |           6900 |
|  8 | 2000 | USA     | Computer   |   1500 |           6900 |
| 10 | 2001 | USA     | Computer   |   1500 |           6900 |
| 11 | 2001 | USA     | Computer   |   1200 |           6900 |
|  2 | 2000 | Finland | Phone      |    100 |            110 |
|  3 | 2001 | Finland | Phone      |     10 |            110 |
| 12 | 2001 | USA     | TV         |    150 |            250 |
| 13 | 2001 | USA     | TV         |    100 |            250 |
+----+------+---------+------------+--------+----------------+


ROWS, PRECEDING, FOLLOWING

上の公式ドキュメントのように他にもウィンドウ関数は面白い使い道があります.

例えば1つ前のレコードとの合計値を求めたいときなどです.以下のようにSQLを書くと1つ小さいのidとの合計値がone_preceding_profitになります.

SELECT
 *,
   SUM(profit) OVER(ORDER BY id ROWS 1 PRECEDING) AS one_preceding_profit
FROM sales;
+----+------+---------+------------+--------+----------------------+
| id | year | country | product    | profit | one_preceding_profit |
+----+------+---------+------------+--------+----------------------+
|  1 | 2000 | Finland | Computer   |   1500 |                 1500 |
|  2 | 2000 | Finland | Phone      |    100 |                 1600 |
|  3 | 2001 | Finland | Phone      |     10 |                  110 |
|  4 | 2000 | India   | Calculator |     75 |                   85 |
|  5 | 2000 | India   | Calculator |     75 |                  150 |
|  6 | 2000 | India   | Computer   |   1200 |                 1275 |
|  7 | 2000 | USA     | Calculator |     75 |                 1275 |
|  8 | 2000 | USA     | Computer   |   1500 |                 1575 |
|  9 | 2001 | USA     | Calculator |     50 |                 1550 |
| 10 | 2001 | USA     | Computer   |   1500 |                 1550 |
| 11 | 2001 | USA     | Computer   |   1200 |                 2700 |
| 12 | 2001 | USA     | TV         |    150 |                 1350 |
| 13 | 2001 | USA     | TV         |    100 |                  250 |
+----+------+---------+------------+--------+----------------------+

id = 1は1つ小さいidがないので1500, id = 2は1500 + 100で1600といった具合になっています.
PRECEDINGは「前の」というニュアンスで用いられており,[数値] PRECEDING で何行前までのレコードを範囲とするかを指定できます.なので,
5 PRECEDING とすると5行前までのレコード(+現在のレコード)を指定できます.

また以下のSQLのようにすれば,前後のレコードについての操作ができます.

SELECT
   *,
   SUM(profit) OVER(ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS one_pf_profit
FROM sales;
+----+------+---------+------------+--------+---------------+
| id | year | country | product    | profit | one_pf_profit |
+----+------+---------+------------+--------+---------------+
|  1 | 2000 | Finland | Computer   |   1500 |          1600 |
|  2 | 2000 | Finland | Phone      |    100 |          1610 |
|  3 | 2001 | Finland | Phone      |     10 |           185 |
|  4 | 2000 | India   | Calculator |     75 |           160 |
|  5 | 2000 | India   | Calculator |     75 |          1350 |
|  6 | 2000 | India   | Computer   |   1200 |          1350 |
|  7 | 2000 | USA     | Calculator |     75 |          2775 |
|  8 | 2000 | USA     | Computer   |   1500 |          1625 |
|  9 | 2001 | USA     | Calculator |     50 |          3050 |
| 10 | 2001 | USA     | Computer   |   1500 |          2750 |
| 11 | 2001 | USA     | Computer   |   1200 |          2850 |
| 12 | 2001 | USA     | TV         |    150 |          1450 |
| 13 | 2001 | USA     | TV         |    100 |           250 |
+----+------+---------+------------+--------+---------------+

1 PRECEDING AND 1 FOLLOWING で前後の1レコード(+現在のレコード)を指定して,その合計値がone_pf_profitになっています.

FOLLOWINGは「後の」というニュアンスで用いられており,[数値] FOLLOWING で何行後までのレコードを範囲とするかを指定できます.なので,5 FOLLOWING とすると5行後までのレコード(+現在のレコード)を指定できます.


あとがき

ウィンドウ関数を初めて見たときは「こんなの使ってたら泡噴くで...」と思っていたのですが,整理してみるとサブクエリとかの代用とかで意外と使えそうな気がしました(アウトプットの効果ってやつか).難しそうなことでも,時間かけて1つずつ確認するとわかるもんですな...


この記事が気に入ったらサポートをしてみませんか?