demo: db <> fiddle
Решение с оконной функцией row_number
(https://www.postgresql.org/docs/current/static/tutorial-window.html)
SELECT
customer, order_date, order_total
FROM (
SELECT
*,
first_value(order_date) OVER w as last_order,
first_value(order_total) OVER w as last_total,
row_number() OVER w as row_count
FROM orders
WINDOW w AS (PARTITION BY customer ORDER BY order_date DESC)
) s
WHERE row_count = 1 AND order_date < CURRENT_DATE - 30
Решение с DISTINCT ON
(https://www.postgresql.org/docs/9.5/static/sql-select.html#SQL-DISTINCT):
SELECT
customer, order_date, order_total
FROM (
SELECT DISTINCT ON (customer)
*,
first_value(order_date) OVER w as last_order,
first_value(order_total) OVER w as last_total
FROM orders
WINDOW w AS (PARTITION BY customer ORDER BY order_date DESC)
ORDER BY customer, order_date DESC
) s
WHERE order_date < CURRENT_DATE - 30
Объяснение:
В обоих решениях я работаю с оконной функцией first_value
. Рамка оконной функцииопределяется клиентами. Строки в группах клиентов упорядочены по убыванию по дате, что дает последнюю строку первой (last_value
не работает, как ожидалось, каждый раз ). Таким образом, можно получить последнююorder_date
и последние order_total
этого порядка.
Разница между решениями заключается в фильтрации. Я показал обе версии, потому что иногда одна из них значительно быстрее
Стиль оконной функциисоздает количество строк в кадрах. Каждая первая строка может быть отфильтрована позже. Это достигается путем добавления оконной функции row_number
. Преимущество этого решения проявляется, когда вы пытаетесь отфильтровать первые два или три набора данных.Вы просто чПопробуйте изменить фильтр с WHERE row_count = 1
на WHERE row_count = 2
Но если вы хотите, чтобы в каждой группе была только одна строка, вам просто нужно убедиться, что ожидаемая строка в каждой группе упорядочена как первая строка в группе.,Затем функция DISTINCT ON
может удалить все последующие строки.DISTINCT ON (customer)
дает первую (упорядоченную) строку для customer
группы.