[解決済み] SQL結合:1対多の関係で最後のレコードを選択する
質問
顧客のテーブルと購入のテーブルがあるとします。各購入は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で実行します。
サブクエリを使用する人もいますが、私はこの方法を使用することで、より簡単にタイを解決することができます。
関連
-
[解決済み] リストの最後の要素を取得する方法
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] SQL ServerでJOINを使用してUPDATE文を実行するにはどうすればよいですか?
-
[解決済み] 各グループの最後のレコードを取得する - MySQL
-
[解決済み] PostgreSQLからのPL/pgSQL出力をCSVファイルに保存する
-
[解決済み] SQL JOIN - WHERE句とON句の比較
-
[解決済み] フラットテーブルをツリーにパースする最も効率的/エレガントな方法は何ですか?
-
[解決済み] SQL ServerでINSERT INTOとしてデータをエクスポートする
-
[解決済み】「INNER JOIN」と「OUTER JOIN」の違いは何ですか?
-
[解決済み] SQL ServerでINNER JOINを使用して削除するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
解決策:ユーザー root で localhost:3306 にある MySQL に接続できませんでした。
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] SQL Server - 挿入された行のIDを取得するための最良の方法は?
-
[解決済み] JOINとINNER JOINの違いについて
-
[解決済み] ある列の最大値を持つ行を取得する
-
[解決済み] SQLite - UPSERT *not* INSERT or REPLACE
-
[解決済み] フラットテーブルをツリーにパースする最も効率的/エレガントな方法は何ですか?
-
[解決済み] SQLのインデックスとは何ですか?
-
[解決済み] 別のテーブルに一致する項目がない行を選択するにはどうすればよいですか?
-
[解決済み] Postgres でサブクエリを使用してテーブルの行を更新する