次のようなデータがあります。
entities
id name
1 Apple
2 Orange
3 Banana
定期的にプロセスが実行され、各エンティティにスコアが付けられます。プロセスはデータを生成し、次のようにスコアテーブルに追加します。
scores
id entity_id score date_added
1 1 10 1/2/09
2 2 10 1/2/09
3 1 15 1/3/09
4 2 10 1/03/09
5 1 15 1/4/09
6 2 15 1/4/09
7 3 22 1/4/09
すべてのエンティティと、それぞれの最新の記録スコアを選択できるようにしたいので、次のようなデータが得られます。
entities
id name score date_added
1 Apple 15 1/4/09
2 Orange 15 1/4/09
3 Banana 15 1/4/09
このクエリを使用して、単一のエンティティのデータを取得できます。
SELECT entities.*,
scores.score,
scores.date_added
FROM entities
INNER JOIN scores
ON entities.id = scores.entity_id
WHERE entities.id = ?
ORDER BY scores.date_added DESC
LIMIT 1
しかし、すべてのエンティティに同じものを選択する方法に困惑しています。おそらくそれは私を顔で見つめているのでしょうか?
ご清聴ありがとうございました。
素晴らしい反応をありがとう。希望する解決策が浮上するかどうかを確認するために数日与えてから、答えを選択します。
更新:提案されたソリューションのいくつかを試してみましたが、現在直面している主な問題は、エンティティがまだ生成されたスコアを持っていない場合、リストに表示されないことです。
まだスコアが投稿されていない場合でも、すべてのエンティティが確実に返されるようにするには、SQLはどのようになりますか?
更新:回答が選択されました。みんな、ありがとう!
私はこのようにします:
SELECT e.*, s1.score, s1.date_added
FROM entities e
INNER JOIN scores s1
ON (e.id = s1.entity_id)
LEFT OUTER JOIN scores s2
ON (e.id = s2.entity_id AND s1.id < s2.id)
WHERE s2.id IS NULL;
私のバリエーションを追加するだけです:
SELECT e.*, s1.score
FROM entities e
INNER JOIN score s1 ON e.id = s1.entity_id
WHERE NOT EXISTS (
SELECT 1 FROM score s2 WHERE s2.id > s1.id
)
アプローチ1
SELECT entities.*,
scores.score,
scores.date_added
FROM entities
INNER JOIN scores
ON entities.id = scores.entity_id
WHERE scores.date_added =
(SELECT max(date_added) FROM scores where entity_id = entities.id)
アプローチ2
バッチに対するクエリコスト:
SELECT entities.*,
scores.score,
scores.date_added
FROM entities
INNER JOIN scores
ON entities.id = scores.entity_id
inner join
(
SELECT
entity_id, max(date_added) as recent_date
FROM scores
group by entity_id
) as y on entities.id = y.entity_id and scores.date_added = y.recent_date
これは古い質問であり、誰もまだ言及していないアプローチを追加すると思いました。Cross Apply
またはOuter Apply
。これらはSQL Server 2005で利用可能です(この質問ではデータベースタイプはタグ付けされていません)またはそれ以上
一時テーブルを使用する
DECLARE @Entities TABLE(Id INT PRIMARY KEY, name NVARCHAR(MAX))
INSERT INTO @Entities
VALUES (1, 'Apple'), (2, 'Orange'), (3, 'Banana'), (4, 'Cherry')
DECLARE @Scores TABLE(Id INT PRIMARY KEY, Entity_Id INT, Score INT, Date_Added DATE)
INSERT INTO @Scores
VALUES (1,1,10,'2009-02-01'),
(2,2,10,'2009-02-01'),
(3,1,15,'2009-02-01'),
(4,2,10,'2009-03-01'),
(5,1,15,'2009-04-01'),
(6,2,15,'2009-04-01'),
(7,3,22,'2009-04-01')
使用できます
SELECT E.Id, E.name, S.Score, S.Date_Added
FROM @Entities E
CROSS APPLY
(
SELECT TOP 1 *
FROM @Scores Sc
WHERE Sc.Entity_Id = E.Id
ORDER BY sc.Score DESC
) AS S
望ましい結果を得るために。スコアのないエンティティを許可する同等の権限は
SELECT E.Id, E.name, S.Score, S.Date_Added
FROM @Entities E
OUTER APPLY
(
SELECT TOP 1 *
FROM @Scores Sc
WHERE Sc.Entity_Id = E.Id
ORDER BY sc.Score DESC
) AS S
SELECT entities.*,
scores.score,
scores.date_added
FROM entities
INNER JOIN scores
ON entities.id = scores.entity_id
WHERE entities.id in
(select id from scores s2 where date_added = max(date_added) and s2.id = entities.id)
ORDER BY scores.date_added DESC
LIMIT 1
ROW_NUMBERなどのウィンドウ関数を使用した自然なクエリを使用して、ほとんどのRDBMS(Oracle、PostgreSQL、SQL Server)で今日これを行うこともできます。
SELECT id, name, score, date_added FROM (
SELECT e.id, e.name, s.score, s.date_added,
ROW_NUMBER() OVER (PARTITION BY e.id ORDER BY s.date_added DESC) rn
FROM Entities e INNER JOIN Scores s ON e.id = s.entity_id
) tmp WHERE rn = 1;