■ はじめに
SQL の Window関数 (分析関数) について扱う。 PostgeSQLだけでなく、Redshiftでも使える。 今回は、その中で、 LAG / LEAD に絞る。 なお、ROW_NUMBER / RANK については、 以前やった以下の関連記事を参照のこと。
ROW_NUMBER / RANK + PARTITION BY
https://dk521123.hatenablog.com/entry/2021/03/11/210937
目次
【1】Window関数 【2】構文 1)OVER PARTITION BY (グループ分け) 2)OVER ORDER BY (順序指定) 3)OVER ROWS BETWEEN (レコード範囲) 4)補足:組み合わせについて 【3】利用可能なWindow関数 【4】独自のWindow関数 【5】サンプル 例1:最新5年間の売上増減を表示 例2:マラソン大会の5kmペースの前後比較をする
【1】Window関数
* テーブルから部分集合を切り出して処理をかける機能 * 集約関数は、GroupBy句で区切られた集合に対しての処理するのに対し、 Windowで区切られた集合に対しての処理
使用例
* サブクエリー等を使わずに1つ前・後の行の値を取得可能
DB
* PostgreSQL / Redshift でも使える
【2】構文
1)OVER PARTITION BY (グループ分け)
* OVER 句にて、 PARTITION BY 句で指定した 項目の値ごとに部分集合を作る * 以下の関連記事でも扱っている。
https://dk521123.hatenablog.com/entry/2021/03/11/210937
構文
-- パーティション分割 関数(...) OVER (PARTITION BY カラム名, ...)
2)OVER ORDER BY (順序指定)
* OVER 句にて、部分集合内を ORDER BY 句で指定した条件でソート
構文
-- 区間ごとに並び替え 関数(...) OVER (ORDER BY カラム名, ...)
3)OVER ROWS BETWEEN (レコード範囲)
構文
-- 区間ごとに並び替え 関数(...) OVER (ROWS BETWEEN 開始位置 AND 終了位置)
4)補足:組み合わせについて
* PARTITION BY と ORDER BY の組み合わせ も使用可能
サンプル
-- 項目「category」に対して、PARTITION BYして -- 項目 date1, date2 と 複数指定した場合 RANK() OVER (PARTITION BY category date1 DESC, date2 DESC) AS rank_by_latest
【3】利用可能なWindow関数
* 他にもいっぱいあるけど、、、
# | 関数 | 説明 |
---|---|---|
1 | lag() | 現在の行よりソート状態での前の行の値を返す |
2 | lead() | 現在の行よりソート状態での後の行の値を返す |
3 | row_number() | Window内での現在行の数を返す |
4 | rank() | Window内での現在行の順位を返す |
PostgreSQL
https://www.postgresql.jp/document/8.4/html/functions-window.html
【4】独自のWindow関数
* 独自Window関数作成可能みたい
【5】サンプル
例1:最新5年間の売上増減を表示
以下の関連記事で行った「最新5年間の売上増減を表示」を LAG() と OVER(ORDER BY) を使って実装してみる。
考え方
[1] OVER(ORDER BY year ASC) で年を昇順に並べ替える [2] 呼び出される LAG(sales) で前の売上 (sales) を取得する
https://dk521123.hatenablog.com/entry/2021/08/26/222043
SQL文 - LAG()のサンプル
SELECT main.year AS year, CASE WHEN main.sales = main.previous_sales THEN '→' WHEN main.sales > main.previous_sales THEN '↑' WHEN main.sales < main.previous_sales THEN '↓' ELSE '-' END AS up_or_down, main.sales AS sales, main.previous_sales AS previous_sales, main.sales - main.previous_sales AS diff FROM ( SELECT year AS year, sales AS sales, -- ★ここに注目★ LAG(sales) OVER(ORDER BY year ASC) AS previous_sales FROM sales ORDER BY year DESC ) AS main ;
例2:マラソン大会の5kmペースの前後比較をする
create table marathon( km numeric, pace time ); insert into marathon values (5,'00:14:53'), (10,'00:29:46'), (15,'00:44:32'), (20,'00:59:21'), (25,'01:14:09'), (30,'01:28:59'), (35,'01:44:01'), (40,'01:58:40'), (42.195,'02:04:56'); select km, pace, lag(pace, 1) over (order by km) as lag_pace, --前の結果を取得 lead(pace, 1) over (order by km) as lead_pace --後の結果を取得 from marathon;
km | pace | lag_pace | lead_pace |
---|---|---|---|
5 | 00:14:53 | 00:29:46 | |
10 | 00:29:46 | 00:14:53 | 00:44:32 |
15 | 00:44:32 | 00:29:46 | 00:59:21 |
20 | 00:59:21 | 00:44:32 | 01:14:09 |
25 | 01:14:09 | 00:59:21 | 01:28:59 |
30 | 01:28:59 | 01:14:09 | 01:44:01 |
35 | 01:44:01 | 01:28:59 | 01:58:40 |
40 | 01:58:40 | 01:44:01 | 02:04:56 |
42.195 | 02:04:56 | 01:58:40 |
参考文献
https://qiita.com/niwasawa/items/6b9a771ce94090059aab
https://dev.classmethod.jp/articles/sql-window-function/
https://excel-ubara.com/vba_sql/vba_SQL023.html
PostgreSQL
https://lets.postgresql.jp/documents/technical/window_functions/1
https://qiita.com/HiromuMasuda0228/items/0b20d461f1a80bd30cfc
http://everything-you-do-is-practice.blogspot.com/2017/09/postgresql-lag-lead.html
前後のレコードの値を取得するSQL – LAGとLEAD | Box Code
関連記事
Window関数 ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/02/22/000000
Window関数 ~ ROW_NUMBER ~
https://dk521123.hatenablog.com/entry/2021/09/10/092850
Window関数 ~ ROW_NUMBER / RANK + PARTITION BY ~
https://dk521123.hatenablog.com/entry/2021/03/11/210937
Window関数 ~ RANK / DENSE_RANK ~
https://dk521123.hatenablog.com/entry/2012/08/15/225233
【SQL】ストアドプロシージャ / ファンクション
https://dk521123.hatenablog.com/entry/2010/08/06/112528
【PostgreSQL】ストアドファンクション
https://dk521123.hatenablog.com/entry/2014/04/21/000100
WITH句 ~ 共通テーブル式 ~
https://dk521123.hatenablog.com/entry/2012/07/26/013620
SQL View (ビュー)
https://dk521123.hatenablog.com/entry/2011/11/14/021253
SQLで変化(増加/変化なし/減少)について考える
https://dk521123.hatenablog.com/entry/2021/08/26/222043
グループ内のMAXデータを取得する
https://dk521123.hatenablog.com/entry/2018/10/06/230841