#sql #postgresql #distinct-on
Вопрос:
Модель Subscription
has_many
SubscriptionCart
.
У SubscriptionCart
А есть а status
и authorized_at
дата.
Мне нужно выбрать корзину с самой старой authorized_at
датой из всех тележек , связанных с a Subscription
, а затем я должен упорядочить все возвращенные Subscription
результаты по этому subscription_carts.authorized_at
столбцу.
Приведенный ниже запрос работает, но я не могу понять, как выбрать DISTINCT ON subscription.id
, чтобы избежать дублирования, но ORDER BY subscription_carts.authorized_at
.
необработанный sql-запрос до сих пор:
select distinct on (s.id) s.id as subscription_id, subscription_carts.authorized_at, s.* from subscriptions s join subscription_carts subscription_carts on subscription_carts.subscription_id = s.id and subscription_carts.plan_id = s.plan_id where subscription_carts.status = 'processed' and s.status IN ('authorized','in_trial', 'paused') order by s.id, subscription_carts.authorized_at
Если я попытаюсь ORDER BY subscription_carts.authorized_at
сделать это первым, я получу ошибку, потому DISTINCT ON
ORDER BY
что выражения и должны быть в одном и том же порядке.
Решения, которые я нашел, кажутся слишком сложными для того, что мне нужно, и я не смог их реализовать, потому что не понимаю их полностью.
Было бы лучше GROUP BY subscription_id
, а затем выбрать из этой группы вместо использования DISTINCT ON
? Любая помощь будет признательна.
Комментарии:
1. Используйте подзапрос и порядок в конечном результате
2. Не могли бы вы быть более конкретными? Подзапрос для выбора даты min authorized_at из группы subscription_carts?
Ответ №1:
Это требование необходимо для выполнения DISTINCT ON
работы; чтобы изменить окончательный порядок, вы можете добавить внешний запрос с другим ORDER BY
предложением:
SELECT * FROM (SELECT DISTINCT ON (s.id) s.id as subscription_id, subscription_carts.authorized_at, s.* FROM subscriptions s JOIN ... WHERE ... ORDER BY s.id, subscription_carts.authorized_at ) AS subq ORDER BY authorized_at;
Ответ №2:
Вам не нужно использовать DISTINCT ON
. Хотя иногда это бывает полезно, лично я нахожу подходы, основанные на оконных функциях, гораздо более понятными:
-- Optionally, list all columns explicitly, to remove the rn column again SELECT * FROM ( SELECT s.id AS subscription_id, c.authorized_at, s.*, ROW_NUMBER () OVER (PARTITION BY s.id ORDER BY c.authorized_at) rn FROM subscriptions s JOIN subscription_carts c ON c.subscription_id = s.id AND c.plan_id = s.plan_id WHERE c.status = 'processed' AND s.status IN ('authorized', 'in_trial', 'paused') ) t WHERE rn = 1 ORDER BY subscription_id, authorized_at