Этот запрос сложнее перефразировать правильно, чем выглядит.
В настоящее время принятый ответ на основе соединения неправильно обрабатывает случай, когда две строки-кандидаты имеют одинаковое заданное значение purchased_at
: он вернет обе строки.
Вы можете получить правильное поведение следующим образом:
SELECT * FROM purchases AS given
WHERE product_id = 2
AND NOT EXISTS (
SELECT NULL FROM purchases AS other
WHERE given.address_id = other.address_id
AND (given.purchased_at < other.purchased_at OR given.id < other.id)
)
ORDER BY purchased_at DESC
Обратите внимание, что у него есть запасной вариант сравнения значений id
для устранения неоднозначности в случае совпадения значений purchased_at
. Это гарантирует, что условие может быть истинным только для одной строки из тех, которые имеют одинаковое значение address_id
.
Исходный запрос с использованием DISTINCT ON
обрабатывает этот случай автоматически!
Также обратите внимание на способ, которым вы вынуждены кодировать тот факт, что вы хотите «последний раз для каждого address_id
» дважды, как в условии given.purchased_at < other.purchased_at
, так и в предложении ORDER BY purchased_at DESC
, и вы должны убедиться, что они матч. Мне пришлось потратить несколько лишних минут, чтобы убедить себя, что этот запрос действительно верен.
Намного проще написать этот запрос правильно и понятно, если использовать DISTINCT ON
вместе с внешним подзапросом, как предлагает dbenhur .