ProgrammingSQLアナリスト

複数の列に重複する複雑なデータ構造から、どのようにユニークなレコードを抽出し、DISTINCT、GROUP BY、ROW_NUMBER()の動作の違いは何ですか?

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

回答。

SQLにおけるユニークなレコードの抽出は、組織がマルチ次元データを保存するようになったことで、非常に重要なタスクとなりました。時には、複数の列の組み合わせに基づいてユニークな行を出力する必要があり、時には単一のキーのみに基づいて出力することもあります。

問題の歴史:

SQLの初期バージョンは重複をフィルタリングするためにDISTINCTのみを提供していました。その後、GROUP BYなどの構造的手法や、ROW_NUMBER()のようなウィンドウ関数が登場し、重複を扱うより柔軟なシナリオが可能になりました。たとえば、「最後の」または「最初の」レコードを抽出する際に使用します。

問題:

DISTINCTはSELECTのフィールドセットレベルでのみ機能し、GROUP BYは集計を必要とします。ウィンドウ関数は高度なロジックを提供しますが、行を選択する順序を考慮しないと、エラーが発生することがあります。開発者はこれらのアプローチを混同し、間違いが誤った結果を引き起こすことがよくあります。

解決策:

  • 必要なフィールドに対してユニークな行を取得するにはDISTINCTを使用します。
  • 集計(例えば、ユニークなペアに対する合計や日付)が必要な場合はGROUP BYを使用します。
  • 「重複グループからの1つの行の選択」といったタスクにはウィンドウ関数(ROW_NUMBER())を使用します。

コード例:

各顧客についての最新の注文情報を取得します:

WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;

重要なポイント:

  • DISTINCTは、SELECTに指定されたフィールドに対してのみユニークな行を返します。
  • GROUP BYは、集計が必要な場合に必須です。
  • ROW_NUMBER()は、必要な優先度/日付/バージョンでの行選択に非常に柔軟です。

トリッキーな質問。

GROUP BYなしで集計関数と一緒にDISTINCTを使用できますか?

いいえ、集計関数はグループ化を必要とするため、構文エラーが発生します。

SELECT COUNT(DISTINCT CustomerID) -- 正しい SELECT SUM(Amount), DISTINCT CustomerID -- エラー!

GROUP BYでSELECT内のすべての非集計フィールドを指定しないとどうなりますか?

ほとんどのDBMSではエラーが発生します。SELECT内のすべてのフィールドは、集計関数以外はGROUP BYに列挙する必要があります。

サブクエリなしでウィンドウ関数を使って重複を「取り除く」ことはできますか?

いいえ:1つのSELECT内でROW_NUMBER()を使用しても自動的に「重複」をフィルタリングしないため、必要な行を選択するための外部クエリが必要です。

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

  • 多数の列と行に対してDISTINCTを使用すると、パフォーマンスが急激に低下します。
  • 必要な集計なしのGROUP BYは無意味でリソースを消費します。
  • 後続のフィルタなしのウィンドウ関数では重複したデータが返されます。

実生活の例

ネガティブケース

20百万行のテーブルに対して全ての列でDISTINCTを選択した場合:クエリは数時間かかり、最終的にはタイムアウトまたはDBのパフォーマンスの低下がありました。

利点:

  • 書きやすい。

欠点:

  • 大規模データでは非常に非効率的です。

ポジティブケース

ウィンドウ関数を使用:顧客ごとに必要な最新のレコードのみをミリ秒で取得し、前の重複は読み込まれませんでした。

利点:

  • 非常に高いパフォーマンス。
  • 柔軟性。

欠点:

  • 適切なクエリのアーキテクチャとウィンドウ関数の知識が必要です。