例えば、SELECT product_name, price, RANK() OVER (ORDER BY price DESC) AS price_rank FROM productsというクエリでは、製品の価格に基づいて順位付けを行います。
また、SELECT sale_date, amount, LAG(amount, 1, 0) OVER (ORDER BY sale_date) AS previous_day_amount FROM salesというクエリでは、前日の売上額を取得できます。これらの関数を組み合わせることで、複雑なデータ分析を効率的に実行できます。
例えば、顧客ごとの購入履歴を分析する場合、PARTITION BY customer_idを使用することで、各顧客のデータが個別のパーティションに分割され、それぞれの顧客に対して個別に集計やランキングを行うことができます。
具体的には、SELECT customer_id, order_date, order_amount, SUM(order_amount) OVER (PARTITION BY customer_id ORDER BY order_date) AS cumulative_order_amount FROM ordersというクエリでは、顧客ごとの注文日ごとの累積注文金額を計算できます。
window_frame_clauseは、ウィンドウ関数の集計範囲をさらに詳細に指定するために使用されます。例えば、ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWINGという指定は、現在の行の前後の1行を含む範囲を集計対象とすることを意味します。
具体的には、SELECT order_date, order_amount, AVG(order_amount) OVER (ORDER BY order_date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_average FROM ordersというクエリでは、注文日ごとの移動平均を計算できます。
ウィンドウ関数は、標準SQLの構文に組み込んで使用します。基本的な構文は、SELECT句内で関数を呼び出し、OVER句でパーティションや順序を指定する形です。例えば、SELECT function_name(argument) OVER (PARTITION BY column1 ORDER BY column2) FROM table_name WHERE condition のように記述します。FROM句でデータソースとなるテーブルを指定し、WHERE句で条件を絞り込むことも可能です。
SELECT customer_id, purchase_date, purchase_amount,
SUM(purchase_amount) OVER (PARTITION BY customer_id ORDER BY purchase_date)
FROM purchase_history
WHERE purchase_date BETWEEN '2023-01-01' AND '2023-12-31';
OVER句は、ウィンドウ関数の動作を定義する上で非常に重要です。PARTITION BY句を使用すると、データを特定の列の値に基づいてグループ化できます。例えば、OVER (PARTITION BY category) と記述すると、category 列の値が同じ行が同じパーティションに属します。ORDER BY句を使用すると、各パーティション内の行の順序を指定できます。例えば、OVER (PARTITION BY category ORDER BY sales DESC) と記述すると、category ごとに sales の降順で行が並べられます。
複数のパーティションやソート条件を指定することも可能です。例えば、OVER (PARTITION BY region, category ORDER BY sales DESC, date ASC) と記述すると、region と category の組み合わせごとにパーティションが作成され、sales の降順、date の昇順でソートされます。以下に具体的なクエリ例を示します。
SELECT product_name, region, category, sales,
RANK() OVER (PARTITION BY region, category ORDER BY sales DESC) AS rank
FROM sales_data
WHERE date = CURRENT_DATE();
このクエリでは、各地域とカテゴリにおける製品の売上ランキングを計算しています。PARTITION BY と ORDER BY を組み合わせることで、より複雑なデータ分析が可能になります。
window_frame_clauseの指定方法
window_frame_clauseは、ウィンドウ関数の計算対象となる行の範囲をさらに詳細に指定するために使用されます。ROWSとRANGEは、それぞれ行数と値の範囲に基づいてフレームを定義します。ROWS BETWEENを使用すると、物理的な行数に基づいて範囲を指定できます。例えば、ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING は、現在の行の前後の1行を含めた3行を計算対象とします。
RANGE BETWEENを使用すると、値の範囲に基づいて範囲を指定できます。例えば、RANGE BETWEEN 100 PRECEDING AND 100 FOLLOWING は、現在の行の値から前後100の範囲内の行を計算対象とします。フレームの開始位置と終了位置は、UNBOUNDED PRECEDING(パーティションの最初から)、CURRENT ROW(現在の行)、UNBOUNDED FOLLOWING(パーティションの最後まで)などのキーワードで指定できます。以下に具体的なクエリ例を示します。
SELECT date, sales,
AVG(sales) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_average
FROM daily_sales
WHERE date BETWEEN '2024-01-01' AND '2024-01-31';
例えば、店舗ごとの売上ランキングを算出するケースを考えてみましょう。以下のクエリは、store_idごとに売上salesのランキングを計算します。RANK() OVER (PARTITION BY store_id ORDER BY sales DESC)という構文を使用することで、各店舗内での売上順位が算出されます。
SELECT
store_id,
sales,
RANK() OVER (PARTITION BY store_id ORDER BY sales DESC) AS sales_rank
FROM
project_id.dataset.sales_data;
SELECT
stock_date,
price,
LAG(price, 1, 0) OVER (ORDER BY stock_date) AS previous_price,
price - LAG(price, 1, 0) OVER (ORDER BY stock_date) AS price_difference
FROM
project_id.dataset.stock_prices;
このクエリでは、LAG(price, 1, 0) OVER (ORDER BY stock_date)という構文を使用しています。ここで、1は前の行からどれだけ遡るかを示し、0は最初の行にLAGが存在しない場合に返すデフォルト値を指定しています。
SELECT
sale_date,
sales,
AVG(sales) OVER (ORDER BY sale_date ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_average
FROM
project_id.dataset.daily_sales;
このクエリでは、AVG(sales) OVER (ORDER BY sale_date ASC ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)という構文を使用しています。ROWS BETWEEN 6 PRECEDING AND CURRENT ROWは、現在の行とその前の6行を含むウィンドウフレームを指定しています。これにより、各日の売上に対して、過去7日間の平均が算出されます。
また、累積和を算出する場合は、SUM関数を使用します。例えば、
SUM(sales) OVER (ORDER BY sale_date ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
SELECT
category,
product,
sales
FROM
(SELECT
category,
product,
sales,
RANK() OVER (PARTITION BY category ORDER BY sales DESC) as rank
FROM
sales_table)
WHERE rank = 1;
SELECT
customer_id,
purchase_date,
LAG(purchase_date, 1, NULL) OVER (PARTITION BY customer_id ORDER BY purchase_date) AS previous_purchase_date,
DATE_DIFF(purchase_date, LAG(purchase_date, 1, NULL) OVER (PARTITION BY customer_id ORDER BY purchase_date), DAY) AS days_since_last_purchase
FROM
purchase_history;
BigQueryでウィンドウ関数を使用する際、構文エラーはよく発生します。ここでは、一般的な構文エラーの事例とその修正方法について解説します。まず、OVER句の書き間違いによるエラーがあります。例えば、SELECT SUM(revenue) as revenue_total OVER (ORDER BY amount DESC) FROM sample_data;というクエリは、Invalid OVER clauseというエラーメッセージを表示します。
これは、OVER句に必要な関数名が不足しているためです。正しくは、SELECT SUM(revenue) OVER (ORDER BY amount DESC) AS revenue_total FROM sample_data;のように、関数名をSUM(revenue)として指定する必要があります。
次に、PARTITION BY句の指定ミスによるエラーがあります。例えば、SELECT dept_code, SUM(sales_amt) AS DEPT_AMT FROM sample_data WHERE dept_code = 'D001' GROUP BY sales_amt;というクエリは、Syntax error on line x: Unexpected keyword GROUPというエラーメッセージを表示します。
これは、PARTITION BY句をGROUP BY句と混同していることが原因です。ウィンドウ関数にはPARTITION BY句が含まれ、GROUP BY句は集約後の結果に適用されます。正しくは、SELECT dept_code, SUM(sales_amt) OVER(PARTITION BY dept_code) AS DEPT_AMT FROM sample_data;のように記述します。
また、集計関数の誤用によるエラーも存在します。例えば、SELECT SUM(user) as total_users FROM sample_data;というクエリは、Invalid function referenceというエラーメッセージを表示します。集計関数が適用される前に、必要なGROUP BY句を追加する必要があります。