解答

CHAPTER 9

031

SQL文(クエリ)

      WITH master AS (
        SELECT user_pseudo_id, event_name,
        (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') AS page_title,
        IF(event_name = "purchase", 1, 0) AS conversion
        FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_20201101`
        ), master2 AS (
        SELECT user_pseudo_id,
        IF(event_name = "scroll" AND page_title = "New | Google Merchandise Store", TRUE, FALSE) AS key_page_scroll,
        conversion
        FROM master
        ), master3 AS (
        SELECT user_pseudo_id, MAX(key_page_scroll) AS key_page_scrolls, MAX(conversion) AS conversions
        FROM master2
        GROUP BY user_pseudo_id
        )

        SELECT key_page_scrolls, COUNT(DISTINCT user_pseudo_id) AS users, SUM(conversions) AS cv_users,
        ROUND(SUM(conversions) / COUNT(DISTINCT user_pseudo_id), 3) AS user_cvr
        FROM master3
        GROUP BY key_page_scrolls
        ORDER BY 1
    

結果テーブル

結果テーブル

解説

できるだけデータの加工状況がわかりやすいよう、WITH句を3つ利用しました。

最初のWITH句であるmasterでは、集計に必要となる情報をすべて取得しています。2つ目ののWITH句であるmaster2は、特定ページをスクロールした場合に「TRUE」、そうでない場合に「FALSE」のフラグを立てています。3つ目のWITH句であるmaster3では[user_pseudo_id]で、スクロールしたユーザかどうかを表す[key_page_scrolls]、コンバージョンしたユーザーであるかどうかを示す[conversions]を取得しています。

取得にあたっては、両者ともMAX関数を利用しています。したがって、特定ページを一度でもスクロールしたユーザー(user_pseudo_id)には「TRUE」が、コンバージョンしたユーザーには何度コンバージョンした場合でも「1」がフラグとして立っています。

WITH句を数珠つなぎで3つも利用したので、メインのSQL文はかなりシンプルになっています。[key_page_scrolls]でグループ化し、ユーザー数を固有の[user_pseudo_id]の種類数でコンバージョンしたユーザーを[convsersions]の合計で集計しています。

032

SQL文(クエリ)

      WITH master AS (
        SELECT user_pseudo_id,
        (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS ga_session_id,
        (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_number') AS ga_session_number,
        IF(event_name = "purchase", 1, 0) AS conversion
        FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_20201101`
        WHERE device.category = "mobile"
        ),master2 AS (
         SELECT CONCAT(user_pseudo_id, ga_session_id) AS unique_session_id
         , MAX(ga_session_number) AS ga_session_number
         , MAX(conversion) AS conversion
         FROM master
         group by user_pseudo_id, ga_session_id
        )

      SELECT ga_session_number, COUNT(DISTINCT unique_session_id) AS sessions,
      SUM(conversion) AS conversions,
      ROUND(SUM(conversion) / COUNT(DISTINCT unique_session_id), 5) AS cvr
      FROM master2
      GROUP BY ga_session_number
      HAVING ga_session_number <= 5
      ORDER BY 1
    

結果テーブル

結果テーブル

解説

数珠つなぎのWITH句を利用しています。最初の仮想テーブル[master]では、メインのSQL文で集計を必要とするフィールドを単純に取得しています。その際、[device.category]を"mobile"に絞り込んでいます。

2番目の仮想テーブルmaster2では[user_pseuso_id]と[ga_session_id]を文字連結した値を[unique_session_id]として定義し、グループ化したうえで、[ga_session_number]および、コンバージョンしたかどうかのフラグである[conversion]をどちらもMAX関数で集計し、取得しています。

メインのSQL文は仮想テーブルmaster2を対象に[ga_session_number]でグループ化しています。集計は、固有の[unique_session_id]の個数をセッションとして、[conversion]の合計をコンバージョン数としてを取得しています。

033

SQL文(クエリ)

      WITH april AS (
        SELECT query
        FROM jissen.searchdata_site_impression
        WHERE query IS NOT NULL AND data_date BETWEEN "2024-04-01" AND "2024-04-30"
        GROUP BY query
        ORDER BY SUM(clicks) DESC
        LIMIT 10
        ), may AS (
        SELECT query
        FROM jissen.searchdata_site_impression
        WHERE query IS NOT NULL AND data_date BETWEEN "2024-05-01" AND "2024-05-31"
        GROUP BY query
        ORDER BY SUM(clicks) DESC
        LIMIT 10
        )

        SELECT query, SUM(impressions) AS sum_imp,
        SUM(clicks) AS sum_clk,
        ROUND(SUM(clicks) / SUM(impressions) * 100, 2) AS ctr,
        ROUND(SUM(sum_top_position) / SUM(impressions) + 1, 1) AS avg_pos
        FROM jissen.searchdata_site_impression
        WHERE data_date BETWEEN "2024-05-01" AND "2024-05-31"
        GROUP BY query
        HAVING query IN (SELECT query FROM april EXCEPT DISTINCT SELECT query FROM may)
        ORDER BY sum_clk DESC
    

結果テーブル

結果テーブル

解説

WITH句を2つ作成しています。1つは「april」と名前をつけた4月のクリック数トップ10のクエリ(query)の仮想テーブル、もう1つは「may」と名前をつけた、5月のクリック数トップ10のクエリ(query)の仮想テーブルです。

本体のSQL文ではクエリ(query)でグループ化したうえで、5月についての表示回数合計、クリック数合計、クリック率、平均掲載順位を集計しています。肝心の「4月にはトップ10に入っていたが、5月には入らなくなってしまった」の条件はHAVING句で[query]が、aprilからmayを差し引く集合演算をして残った[query]に一致するという条件を適用しています。

034

SQL文(クエリ)

      WITH master AS (
        SELECT DATE_TRUNC(data_date, MONTH) AS year_month, url,
        SUM(impressions) AS sum_imp
        FROM jissen.searchdata_url_impression
        WHERE url NOT LIKE ("%sql%") AND query LIKE ("%sql%")
        GROUP BY year_month, url
        )

        SELECT * FROM master
        QUALIFY RANK() OVER(PARTITION BY year_month ORDER BY sum_imp DESC) <= 3
        ORDER BY year_month, sum_imp DESC
    

結果テーブル

結果テーブル

解説

WITH句で、問題文にある「表示回数合計3つまで」という条件以外を満たす仮想テーブルを作成しておき、本体のクエリでQUALIFY句を利用して、RANK関数が出力したランキングを表す整数を、3以下だけに絞り込んでいます。

別解は以下です。WITH句を必ずしも使わなくとも同じ結果を得ることができます。

      SELECT DATE_TRUNC(data_date, MONTH) AS year_month, url,
      SUM(impressions) AS sum_imp
      FROM jissen.searchdata_url_impression
      WHERE url NOT LIKE ("%sql%") AND query LIKE ("%sql%")
      GROUP BY year_month, url
      QUALIFY RANK() OVER(PARTITION BY year_month ORDER BY sum_imp DESC) <= 3
      ORDER BY year_month, sum_imp DESC
    

035

SQL文(クエリ)

      WITH master AS (
        SELECT
        * EXCEPT(hyouka),
        SPLIT(hyouka) AS array_hyouka
        FROM jissen.V_g_form
        )

        SELECT row_hyouka, COUNT(*) AS respondent_count, ROUND(AVG(nps), 2) AS avg_nps
        FROM (
        SELECT nps, row_hyouka
        FROM master
        CROSS JOIN UNNEST(array_hyouka) AS row_hyouka
        )
        GROUP BY row_hyouka
        ORDER BY 3 DESC
    

結果テーブル

結果テーブル

解説

上記の解答は、午前10時前の解答を除外した、ビュー[V_g_form]を利用した回答例です。ビューを利用しない場合には、WITH句を以下の通りに変更する必要があります。

      WITH master AS (
        SELECT
        * EXCEPT(hyouka),
        SPLIT(hyouka) AS array_hyouka
        FROM jissen.g_form
        WHERE 
        PARSE_DATETIME("%Y/%m/%d %H:%M:%S", timestamp) >= DATETIME("2024-05-05 10:00:00")
        )
    

WITH句で、SPLIT関数を利用して[hyouka]カラムの内容を配列に変更しておき、本体のクエリでUNNESTしてフラット化した1列n行のテーブルを、元のテーブルにCROSS JOINしています。

あとは、評価コメントが格納された[row_hyouka]の内容ごとに、行数をカウントしたものをユーザー数[nps]をAVG関数で平均したものを[avg_nps]として取得しています。

サポートページに戻る