Это пример проблемы 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
). Это может позволить сделать внешнее соединение с помощью индекса покрытия. Обязательно протестируйте на своей платформе, потому что оптимизация зависит от реализации. Используйте функции вашей РСУБД для анализа плана оптимизации. Например. EXPLAIN
в MySQL.
Некоторые люди используют подзапросы вместо решения, которое я показываю выше, но я считаю, что мое решение облегчает разрешение связей.