【问题标题】:How to use DISTINCT ON but ORDER BY another expression?如何使用 DISTINCT ON 但 ORDER BY 另一个表达式?
【发布时间】:2021-11-24 12:06:18
【问题描述】:

型号Subscriptionhas_manySubscriptionCart

SubscriptionCart 有一个 status 和一个 authorized_at 日期。

我需要从与Subscription 关联的所有购物车中选择日期最旧的authorized_at 购物车,然后我必须通过此subscription_carts.authorized_at 列订购所有返回的Subscription 结果。

下面的查询正在运行,但我不知道如何选择 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 ONORDER BY 表达式的顺序必须相同。

我发现的解决方案对于我需要的东西来说似乎太复杂了,而且我未能实施它们,因为我不完全理解它们。

使用GROUP BY subscription_id 然后从该组中选择而不是使用DISTINCT ON 会更好吗?任何帮助表示赞赏。

【问题讨论】:

  • 对最终结果使用子查询和排序
  • 你能说得更具体点吗?从一组subscription_carts 中选择最小authorized_at 日期的子查询?

标签: sql postgresql distinct-on


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-06
      • 2019-01-08
      • 1970-01-01
      • 2012-04-05
      • 2012-02-05
      相关资源
      最近更新 更多