documents:proglang:sql:sql-0011
差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン前のリビジョン | |||
| documents:proglang:sql:sql-0011 [2026/05/16 11:37] – [SQLで移動平均を算出] k896951 | documents:proglang:sql:sql-0011 [2026/05/16 11:37] (現在) – k896951 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== 006.SQLで移動平均を算出 ====== | ||
| + | 2020/ | ||
| + | 平均値格納行がおかしかったので修正。 | ||
| + | |||
| + | 2020/ | ||
| + | 職場のTRSHM君に煽られたんでちょっと書く。 | ||
| + | |||
| + | ===== 概要 ===== | ||
| + | |||
| + | * 直近3日の移動平均を出すサンプルコードを掲示する。 | ||
| + | * ウインドウ関数を利用する。サブクエリを連ねるのはさすがに古い。 | ||
| + | |||
| + | |||
| + | ===== データベース準備 ===== | ||
| + | |||
| + | Visual Studioをインストールしていれば多分SQLServer LocalDBが使えると思うので、こちらを利用する。 | ||
| + | |||
| + | データベースの状態が実行中になれば利用可能。\\ | ||
| + | {{: | ||
| + | |||
| + | ===== テーブルとデータの用意 ===== | ||
| + | |||
| + | sqlcmdでインスタンスパイプ名を指定して接続。あとは普通にSQLを実行してデータを定義する。 | ||
| + | |||
| + | <code sql> | ||
| + | CREATE TABLE sample ( | ||
| + | saledate | ||
| + | , | ||
| + | , | ||
| + | ); | ||
| + | go | ||
| + | INSERT INTO sample values(' | ||
| + | go | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | go | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | ===== OVER句に対象レコードの範囲を指定する ===== | ||
| + | |||
| + | PARTITION BY句で範囲を決め、ORDER BY句でレコードの並びを決めたのち、ROWS句で処理対象レコードを明示する。\\ | ||
| + | 以下のクエリだと、 | ||
| + | * < | ||
| + | * < | ||
| + | * < | ||
| + | |||
| + | の3レコードが処理対象になる。日付でソートして" | ||
| + | |||
| + | <code sql> | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,AVG(val) OVER(PARTITION BY code ORDER BY saledate ROWS BETWEEN 1 preceding AND 1 following) as " | ||
| + | FROM sample | ||
| + | go | ||
| + | </ | ||
| + | |||
| + | ただ、単純にこんなのを書くとはまる。\\ | ||
| + | AVG()で指定する項目がNULLだった場合、そのレコードのカウントが入らないので、例えばcode=' | ||
| + | ※NULL, 50, 50 となるので、100÷3ではなく100÷2になる。 | ||
| + | |||
| + | code=' | ||
| + | |||
| + | {{: | ||
| + | ===== NULL値の対応を入れる ===== | ||
| + | |||
| + | 欠損レコードを補いNULL値の影響を消し込む。下手な小細工するより早い。 | ||
| + | <code sql> | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | go | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,AVG(val) OVER(PARTITION BY code ORDER BY saledate ROWS BETWEEN 1 preceding AND 1 following) AS " | ||
| + | FROM sample | ||
| + | GO | ||
| + | </ | ||
| + | {{: | ||
| + | |||
| + | ===== ダミーレコードは出したくない ===== | ||
| + | |||
| + | ダミーレコードを出したくないならテーブルを拡張して対応すればいいと思う。\\ | ||
| + | この例だと計算結果の行セットVを作り、ここからダミー行を除いている。 | ||
| + | |||
| + | <code sql> | ||
| + | DROP TABLE sample | ||
| + | go | ||
| + | CREATE TABLE sample ( | ||
| + | saledate | ||
| + | , | ||
| + | , | ||
| + | , | ||
| + | ); | ||
| + | go | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | INSERT INTO sample values(' | ||
| + | go | ||
| + | WITH V as ( | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,AVG(val) OVER(PARTITION BY code ORDER BY saledate ROWS BETWEEN 1 preceding AND 1 following) as " | ||
| + | ,disp | ||
| + | FROM sample | ||
| + | ) | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,moved_avg | ||
| + | FROM V | ||
| + | WHERE disp=' | ||
| + | go | ||
| + | </ | ||
| + | {{: | ||
| + | |||
| + | もし先頭日と最終日を除きたければ行セットVからその日付を除けばいい。 | ||
| + | <code sql> | ||
| + | WITH V as ( | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,AVG(val) OVER(PARTITION BY code ORDER BY saledate ROWS BETWEEN 1 preceding AND 1 following) as " | ||
| + | ,disp | ||
| + | FROM sample | ||
| + | ) | ||
| + | SELECT saledate | ||
| + | ,code | ||
| + | ,moved_avg | ||
| + | FROM V | ||
| + | WHERE disp=' | ||
| + | AND saledate BETWEEN ' | ||
| + | go | ||
| + | </ | ||
| + | {{: | ||
| + | |||
| + | {{tag> database SQL 不足レコード補填 SQLServer 技術資料}} | ||
documents/proglang/sql/sql-0011.txt · 最終更新: by k896951
