1. ホーム
  2. sql

[解決済み] SQL結合:1対多の関係で最後のレコードを選択する

2022-03-24 18:11:56

質問

顧客のテーブルと購入のテーブルがあるとします。各購入は1人の顧客に属しています。すべての顧客とその最後の購入品のリストを1つの SELECT ステートメントを使用します。ベストプラクティスは何でしょうか?インデックスの構築について何かアドバイスがあれば教えてください。

回答には、これらのテーブル/カラム名を使用してください。

  • 顧客 id , name
  • 購入する。 id , customer_id , item_id , date

また、より複雑な状況では、最後の購入品を顧客テーブルに入れることによってデータベースを非正規化することは(パフォーマンス的に)有益でしょうか?

の場合、(購入) id が日付順にソートされることが保証されている場合、以下のように記述することで簡略化することができます。 LIMIT 1 ?

解決方法は?

の例です。 greatest-n-per-group の問題は、StackOverflowで定期的に登場しています。

私が普段推奨している解決方法は、以下の通りです。

SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
    (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;

説明:行が与えられると p1 という行は存在しないはずです。 p2 同じ顧客で、日付が後のもの(同日の場合は、後の id ). そうであることがわかったら、次に p1 がその顧客の直近の購入品である。

インデックスについては、複合インデックスを purchase カラムの上に ( customer_id , date , id ). これにより、外側joinはカバーリングインデックスを使用して行うことができるかもしれません。 最適化は実装に依存するため、必ずプラットフォーム上でテストしてください。 RDBMSの機能を使って、最適化計画を分析してください。 例 EXPLAIN をMySQLで実行します。


サブクエリを使用する人もいますが、私はこの方法を使用することで、より簡単にタイを解決することができます。