Как использовать DISTINCT ON, но УПОРЯДОЧИТЬ ПО другому выражению?

#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