У меня есть таблица с идентификаторами столбцов, именем, фамилией, созданной (датой).
У меня есть следующая таблица:
ID | Forename | Surname | Created
---------------------------------
1 | Tom | Smith | 2008-01-01
1 | Tom | Windsor | 2008-02-01
2 | Anne | Thorn | 2008-01-05
2 | Anne | Baker | 2008-03-01
3 | Bill | Sykes | 2008-01-20
Basically, I want this to return the most recent name for each ID, so it would return:
ID | Forename | Surname | Created
---------------------------------
1 | Tom | Windsor | 2008-02-01
2 | Anne | Baker | 2008-03-01
3 | Bill | Sykes | 2008-01-20
Я получаю желаемый результат с этим запросом.
SELECT id, forename, surname, created
FROM name n
WHERE created = (SELECT MAX(created)
FROM name
GROUP BY id
HAVING id = n.id);
Я получаю результат, который хочу, но не понимаю, ПОЧЕМУ ИДЕНТИФИКАТОРЫ НЕ ПОВТОРЯЮТСЯ в наборе результатов. Что я понимаю о коррелированном подзапросе, так это то, что он берет одну строку из внешней таблицы запросов и запускает внутренний подзапрос. Разве он не должен повторять «id», когда идентификаторы повторяются во внешнем запросе? Может кто-нибудь объяснить мне, что именно происходит за кулисами?
Во-первых, вашему подзапросу не нужен GROUP BY
. Чаще пишут так:
SELECT n.id, n.forename, n.surname, n.created
FROM name n
WHERE n.created = (SELECT MAX(n2.created)
FROM name n2
WHERE n2.id = n.id
);
Вы должны выработать привычку уточнять ссылки на столбцы все, особенно если ваш запрос содержит несколько ссылок на таблицы.
Я думаю, вы спрашиваете, почему это работает. Ну, каждая строка во внешнем запросе проверяется на условие. Условие: "это мое created
такое же, как максимальное created
для всех строк в таблице name
с одинаковым id
". В ваших данных только одна строка на id
соответствует этому условию, поэтому id
s не повторяются.
Вы также можете рассмотреть возможность объединения таблиц по значениям столбцов created vs max(created):
SELECT n.id, n.forename, n.surname, n.created
FROM name n
RIGHT JOIN ( SELECT id, MAX(created) as created FROM name GROUP BY id ) t
ON n.created = t.created;
или с помощью оператора IN
:
SELECT id, forename, surname, created
FROM name n
WHERE ( id, created ) IN (SELECT id, MAX(created)
FROM name
GROUP BY id );
или используя EXISTS
с предложением HAVING
в подзапросе:
SELECT id, forename, surname, created
FROM name n
WHERE EXISTS (SELECT id
FROM name
GROUP BY id
HAVING MAX(created) = n.created
);
Upwoting это, чтобы сделать заметку для себя. Это правильный способ выполнения таких задач.