使わないとすぐ忘れるのでメモの意味で残しておく
題材はGA4でExportしたデータを使ってpagepathごとの過去7日間、30日間、合計のPV数を集計するという感じでやってみる
公式の解説
分析関数に関してのドキュメントは次にある
標準 SQL の分析関数のコンセプト | BigQuery | Google Cloud
実際のSQL
WITH flattened AS( # 日毎pagepath毎のPV数 # page_locationの値がURLなのでパスの部分のみを抜き出す # 日付は日本時間で集計する SELECT DATE( TIMESTAMP_MICROS(event_timestamp), 'Asia/Tokyo' ) AS d, REGEXP_REPLACE( REGEXP_REPLACE( params.value.string_value, r"https?://swfz.hatenablog.com(.*)", "\\1" ), r"\?.*", "" ) AS pagepath, COUNT(params.key) AS pageview FROM `sample-project-1111111.analytics_123456789.events_*`, UNNEST(event_params) AS params WHERE event_name = 'page_view' AND params.key = 'page_location' GROUP BY pagepath, d ), # 後の集計で最新の日時のレコードが無いと困るので一律でレコードを追加する # 前日分のデータが最新となるので実行時の日付をpagepathの数だけ追加する # 当日分のデータも含める場合はレコードがある場合はそっち、ない場合は追加みたいな感じの書き方にする必要がある combined AS ( ( SELECT CURRENT_DATE() AS d, pagepath, 0 AS pageview FROM flattened GROUP BY pagepath ) UNION ALL ( SELECT * FROM flattened ) ) # 分析関数で過去7日間、過去30日間のPV数をpagepath毎に取得する SELECT d, pagepath, pageview, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) AS is_last7day, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) AS is_last30day, ROW_NUMBER() OVER(PARTITION BY pagepath ORDER BY d DESC ) AS rn, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) ORDER BY d ) AS last7days_pv, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) ORDER BY d ) AS last30days_pv, SUM(pageview) OVER(PARTITION BY pagepath) AS total_pv FROM combined WHERE TRUE QUALIFY rn = 1
結果はこんな感じ
分析関数の部分のメモ書き
下準備の部分は後で見返したときに思い出せるようにコメントで補足した
分析関数を使っている部分に関して
SELECT d, pagepath, pageview, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) AS is_last7day, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) AS is_last30day, ROW_NUMBER() OVER(PARTITION BY pagepath ORDER BY d DESC ) AS rn, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) ORDER BY d ) AS last7days_pv, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) ORDER BY d ) AS last30days_pv, SUM(pageview) OVER(PARTITION BY pagepath) AS total_pv FROM combined WHERE TRUE QUALIFY rn = 1
QUALIFY rn = 1
でrow numberが1のレコードのみを絞っている
この部分をコメントアウトすると理解しやすい
適当なデータを用意して試してみる
現在日時は2021-10-09
WITH sample AS( SELECT * FROM UNNEST(ARRAY<STRUCT<d DATe, pagepath STRING, pageview INT64>> [ ("2021-08-01", "/hoge", 1), ("2021-09-20", "/hoge", 1), ("2021-10-07", "/hoge", 1), ("2021-09-30", "/fuga", 1), ("2021-10-03", "/fuga", 1), ("2021-10-04", "/fuga", 1) ] ) ) SELECT d, pagepath, pageview, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) AS is_last7day, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) AS is_last30day, ROW_NUMBER() OVER(PARTITION BY pagepath ORDER BY d DESC ) AS rn, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY) ORDER BY d ) AS last7days_pv, SUM(pageview) OVER(PARTITION BY pagepath, d >= DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY) ORDER BY d ) AS last30days_pv, SUM(pageview) OVER(PARTITION BY pagepath) AS total_pv FROM sample
- 結果
rn
PARTITION
を用いてpagepath毎で区切りORDER BY
を用いて日付で降順の行番号を出す
is_last7day,is_last30day
d
が過去7,30日以内かどうかの真偽値
last7days_pv,last30days_pv
- pageviewのSUMをpagepathと過去7日以内かどうかの真偽値
d >= DATE_SUB(CURRENT_DATE(), INTERVAL 8 DAY
→区切り日付で昇順に並べて集計する is_last7day
が出現するたびに加算されていく感じ
- pageviewのSUMをpagepathと過去7日以内かどうかの真偽値
total_pv
- pageviewのSUMをpagepathごとに区切り集計する
OVERとORDERを調整してrn = 1
の行にほしい計算結果が出力されるようにする
で最終的な集計結果をQUALIFY rn = 1
で絞るとpagepath毎に過去7日、30日、総計のPV数を算出できる
感想
- 以前分析関数を調べながらSQL書いたが、あとで読んでみたら理解するまで結構時間かかったので今回は残すのと復習も兼ねてメモしたので次使うときは大丈夫なはず
- 日毎の移動平均の算出なども同様な感じで割とサクッと算出できそう
- 下準備が割と面倒(日付×pagepathのデータを出す)でPVがないレコードも埋めたりするとかそういうのが発生してくるともっと面倒な感じになる(今回はやっていない)
他にも良い書き方などありそうだなと思うのでご指摘があれば教えていただけると嬉しいです