Ответ 1
Я делаю так:
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;
У меня есть данные, которые выглядят так:
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 выглядел так, чтобы гарантировать, что все сущности будут возвращены, даже если у них еще нет оценки?
UPDATE: выбран ответ. Спасибо всем!
Я делаю так:
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
Вы также можете сделать это сегодня в большинстве СУБД (Oracle, PostgreSQL, SQL Server) с естественным запросом, используя такие функции окна, как ROW_NUMBER:
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;