0
0

More than 1 year has passed since last update.

分析クエリのメモ

Posted at

前置き

仕事で使っているクエリのメモです
使用DBはトレジャーデータでエンジンはPrestoです
トレジャーデータの独自関数なども含まれています

集約関数

BOOL_OR

IF(BOOL_OR(hoge_flag), NULL, COUNT(DISTINCT user_id) FILTER(WHERE hogehoge_flag AND NOT fugafuga_flag))

hoge_flagが1つでもtrueの場合はNULL。そうじゃない場合は、user_idを重複排除でカウントします。さらに集計の対象をhogehoge_flagがtrueかつfugafuga_flagがfalseのものに絞ります。

BOOL_OR(TD_TIME_RANGE(time, install_timestamp, TD_TIME_ADD(install_timestamp, '30d', 'JST'), 'JST') AND purchase_flag)

TD_TIME_RANGEとのあわせ技で、簡単に言うとインストールから30日以内に購入があったかをチェックしています。

BOOL_AND

BOOL_AND(IF(event_value NOT IN ('N/A', ''), JSON_EXTRACT_SCALAR(JSON_PARSE(event_value), '$.gender'), '') != 'female')

JSON系の関数とのあわせ技です。event_valueカラムにJSON形式で値が入っているので、ゴミデータを除いた後にJSON関数でgenderがfemaleかどうか見てる感じですね。

BOOL_AND(TD_TIME_RANGE(CAST(install_timestamp AS BIGINT), TD_TIME_ADD(TD_SCHEDULED_TIME(), '-72h', 'Asia/Tokyo'), NULL, 'Asia/Tokyo'))

これはTD_TIME_RANGEとのあわせ技で直近72時間でインストールしているかどうかを見ているみたいです。

前後の行の値をとる

LEAD

CASE
  WHEN LEAD(IF(COALESCE(session_count, 0) > 0, 1, 0), 1) OVER (PARTITION BY idfa ORDER BY time_span) IS NULL 
THEN NULL
  WHEN LEAD(IF(COALESCE(session_count, 0) > 0, 1, 0), 1) OVER (PARTITION BY idfa_android_id ORDER BY time_span) = 1 
THEN 1
  ELSE 0
END AS is_activated_30days

こんな感じにCASEと組み合わせたりなんかも昔していました。引数にIFとか渡したりもできます。
やってることは、次の行のsession_countをみて判定しているだけですね。

LAG

COALESCE(total_session_count, 0) - COALESCE(LAG(total_session_count) OVER(PARTITION BY id ORDER BY time), 0)

これはシンプルに前の行との差分をとっているだけ。

JSON系

JSON_EXTRACT_SCALAR(JSON_PARSE(MIN_BY(event_value, time) FILTER(WHERE event_value IS NOT NULL)), '$.hoge_type')

JSON_PARSEでJSON形式の文字列をJSONとして返して、JSON_EXTRACT_SCALARでhoge_typeキーの値を文字列で取得しています。

IF(event_value NOT IN ('N/A', ''), JSON_EXTRACT_SCALAR(JSON_PARSE(event_value), '$.gender'))

BOOL_ANDで紹介したのとほぼ同じですね。
ゴミデータを除いた後にgenderの値を取得しています。

その他

WINDOW関数

BOOL_OR(課金_flag) OVER (PARTITION BY id ORDER BY day
                                         ROWS BETWEEN dormancy_period PRECEDING
                                         AND IF(7 - dormancy_period >= 0, 7 - dormancy_period, 0) FOLLOWING)

ポイントとしてはORDER BY以降のWINDOW (FRAME)部分にも色々書くことができるということですね。
7日以内に課金しているかを見ているらしいです。もう少し簡単に書けそう

MIN_BY(hoge, IF(hpge IS NOT NULL, time)) OVER (PARTITION BY id)

pgeがNULLの行を除いた中でtimeが一番小さいhogeをとっています。
MIN()だとNULLを除いた値をとってくれるけど、MIN_BY()はNULLも含めた値をとっちゃうので、わざわざこう書いています。

URL関数

URLを色々いじれる関数も色々あります。

CARDINALITY(SPLIT(SUBSTR(URL_EXTRACT_PATH(referer), 2), '/')) splited_referer_size

URL_EXTRACT_PATHはディレクトリパスを抽出できる関数です。
この場合はrefererの数を数えているっぽいですね。

SPLIT(SUBSTR(URL_EXTRACT_PATH(referer), 2), '/') splited_referer

そしてこれはrefererを分割して配列で持っているようです
他にも色々なURL関数があります。
参考

LAST_VALUE、MAX関数の罠

どんな罠があるかというと、これらの関数は 現在行までの最後、最大の値 しかとってくれません。
なので使用するときは、「ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING」をつけて明示的に最後の値まで見るようにしなければなりません。

LAST_VALUE(hoge) OVER (PARTITION BY id ORDER BY time 
                                       ROWS BETWEEN UNBOUNDED PRECEDING 
                                       AND UNBOUNDED FOLLOWING) AS last_hoge

ただ、毎回これを書くのはすごくめんどくさいので下記のように書くことが推奨されています

FIRST_VALUE(hoge) OVER (PARTITION BY id ORDER BY time DESC) AS last_hoge

MIN(hoge) OVER (PARTITION BY id ORDER BY time DESC) AS min_hoge

FIRST_VALUEやMINを使用してORDER BY time DESCで並び替えて最後の値をとっています。
ドキュメントにも書かれているので注意しましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0