レイヤー別のフィルタリング(例:最初にフィルタリングし、その後グループごとに合計を計算し、次に全体のセットで)を効率的に構築するためには、ウィンドウ関数(OVER())とネストされたGROUP BYを使用します。
例: 各マネージャーごとの最大注文金額を見つけますが、'paid' ステータスの注文の中からのみ、そしてその後、全マネージャーの中での絶対的な最大値を持つマネージャーの名前を出力します。
WITH PaidOrders AS ( SELECT ManagerID, SUM(OrderAmount) AS TotalPaid FROM Orders WHERE Status = 'paid' GROUP BY ManagerID ), WithMax AS ( SELECT *, MAX(TotalPaid) OVER() AS MaxTotalPaid FROM PaidOrders ) SELECT ManagerID, TotalPaid FROM WithMax WHERE TotalPaid = MaxTotalPaid;
このアプローチ(CTE + ウィンドウ関数)は、多層のフィルタリングと集約を実現します。
トリック: 「グループ化(GROUP BY)の前にWHEREフィルタを実行するのと、後でHAVINGを適用するのと何が違うのでしょうか?これはレポートにどのように影響を与えますか?」
答え: WHEREはグループ化の前に行を除外し、厳密な入力セットを提供します。HAVINGは集約されたグループをフィルタリングするため、一時的に「余分な」行を「残す」可能性があります。フィルタの不一致のために間違った場所でフィルタを使用すると、最終的な集約のエラーやレポートの誤った結果を引き起こすことがよくあります。
-- 'paid'のみに対してWHEREを通じて合計を取得する SELECT ManagerID, SUM(OrderAmount) FROM Orders WHERE Status = 'paid' GROUP BY ManagerID; -- または、全員の合計を計算し、その後HAVINGで削除する SELECT ManagerID, SUM(OrderAmount) FROM Orders GROUP BY ManagerID HAVING SUM(OrderAmount) > 1000;
ストーリー
プロジェクト: 売上報告、監査。
エラー: 開発者はWHEREの代わりにHAVING Status='paid'を適用し、集計は誤って未払いの注文を含むため、年間のKPIが不正確に計算されました。
ストーリー
プロジェクト: 銀行分析。
エラー: 複雑な集約にPARTITION BYなしでウィンドウ関数を適用しようとしたため、集計が全テーブルに対して行われ、グループではなくなりました。部門の予算が不正確に計算され、手動で修正する必要がありました。
ストーリー
プロジェクト: オンラインストア、注文の統計。
エラー: ウィンドウ関数をサブクエリにネストすることを最適化時に考慮せず、そのため、サーバーはデータを繰り返し処理し、クエリは単なる二重GROUP BYよりも20倍遅くなりました。