Programmingバックエンド開発者

SQLにおける条件付き集約をどのように実現するか(たとえば、1つの選択肢の中で異なるステータスごとの合計を計算する)と、ここでの落とし穴は何ですか?

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

回答。

条件付き集約は、1つのクエリ内でさまざまな条件に基づいて値(合計やカウントなど)を集約する必要がある場合に使用されます。歴史的に、SQL開発者はこのような目的を達成するために複数のサブクエリを書く必要があり、各カテゴリごとに結合や集約を別々に行う必要があるため、可読性が低く、パフォーマンスが劣るコードにつながっていました。

問題は、異なる条件で複数の集約を同時に計算することが難しいということです。各集約は通常フィルタリングを必要とし、単純に SUM() または COUNT() を適用しても、集約関数内の必要な条件を考慮しません。

解決策は、集約関数内に CASE 構文を使用し、異なる条件に基づいて集約を「分割」することで、複数の結合を行うことなく実現できるようにします。

コードの例:

SELECT department, SUM(CASE WHEN status = 'approved' THEN amount ELSE 0 END) AS approved_sum, SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS pending_sum, COUNT(CASE WHEN status = 'rejected' THEN 1 END) AS rejected_count FROM payments GROUP BY department;

重要な特徴:

  • 1つのクエリ内で複数の条件に基づいて同時に集約できます。
  • すべてのSQL方言で動作します(構文の正確なサポートは異なる場合があります)。
  • SUMだけでなく、COUNT、AVGなどとも使用できます。

注意が必要な質問。

CASE構文なしで条件付き集約を実現できますか?

不正確な回答は、集約関数と直接WHEREをクエリで使用することです。実際、WHEREは集約前に行をフィルタリングし、各集約列内でフィルタリングしません。

コードの例(不正な方法):

SELECT COUNT(*) FROM payments WHERE status = 'approved'; SELECT COUNT(*) FROM payments WHERE status = 'pending';

これらのクエリは、CASEなしで異なる条件に基づいて1つの結果行に連結することはできません。

条件式内でNULLを使用するとどうなりますか?

CASEが代替値を返さない場合、デフォルトでNULLになり、集約関数はNULLを無視します。

コードの例:

SUM(CASE WHEN status = 'approved' THEN amount END) -- ステータスが 'approved' でない場合はNULLになり、行はSUMで無視されます

CASEの代わりにIFを使用できますか?

一部のSQL方言(例えばMySQL)では可能ですが、そのようなコードは異なるデータベース間での移植性がなくなります。一般的なクエリでは常にCASEを使用してください。

一般的なエラーとアンチパターン

  • WHEREを使用する代わりにCASE内のロジックを使用することは、多くの単一クエリを実行する必要があり、パフォーマンスを低下させます。
  • CASEでELSE 0を指定し忘れると、NULLによる欠落のため不正確なカウント/合計が得られることがあります。
  • 必要なチェックなしでCASEをコピー&ペーストすると、論理エラーや不正確な計算が発生します。

実生活の例

ネガティブケース

アナリストは各ステータスごとの合計を計算しようとし、複数の個別のサブクエリを書きました。外部レポートは複雑になり、新しいステータスを追加するたびにコードを書き換える必要がありました。

利点:

  • 1つのメトリックには簡単に実装できます。 欠点:
  • スケーラビリティが難しく、パフォーマンスが低下し、コードの再利用性が低いです。

ポジティブケース

開発者は1つの共通クエリでCASEを使用し、新しいステータスのための拡張可能なユニバーサルレポートを簡単な編集で作成しました。

利点:

  • 高い可読性、スケーラビリティの簡易性、パフォーマンス。 欠点:
  • CASEの構文とさまざまなDBMSにおけるそのニュアンスに関する知識が必要です。