ProgrammingSQLアナリスト

SQLでウィンドウ関数とグループ化を使用して、レイヤー別のフィルタリングを使用した効率的な集約をどのように実装しますか?アプローチの違いは何ですか、そして開発者がよく犯す間違いは何ですか?

Hintsage AIアシスタントで面接を突破

答え。

レイヤー別のフィルタリング(例:最初にフィルタリングし、その後グループごとに合計を計算し、次に全体のセットで)を効率的に構築するためには、ウィンドウ関数(OVER())とネストされたGROUP BYを使用します。

  • GROUP BYによるグループ化は、選択したフィールドに対してのみ集約します。「外部」の行の影響を排除するには、事前フィルタ(WHERE)を使用する必要があります。
  • ウィンドウ関数は、結果セットにフィルタを適用しながら、特定のデータの断片ごとに集約を計算することを可能にします(例えば、同じグループの行だけの中で)。

例: 各マネージャーごとの最大注文金額を見つけますが、'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倍遅くなりました。