PostgreSQL以不同的顺序按

PostgreSQL以不同的顺序按,sql,postgresql,sql-order-by,distinct-on,Sql,Postgresql,Sql Order By,Distinct On,我要运行此查询: SELECT DISTINCT ON (address_id) purchases.address_id, purchases.* FROM purchases WHERE purchases.product_id = 1 ORDER BY purchases.purchased_at DESC 但我得到了这个错误: PG::Error:Error:SELECT DISTINCT ON表达式必须与初始ORDER BY表达式匹配 添加address\u id作为第一个ORDER

我要运行此查询:

SELECT DISTINCT ON (address_id) purchases.address_id, purchases.*
FROM purchases
WHERE purchases.product_id = 1
ORDER BY purchases.purchased_at DESC
但我得到了这个错误:

PG::Error:Error:SELECT DISTINCT ON表达式必须与初始ORDER BY表达式匹配


添加
address\u id
作为第一个
ORDER BY
表达式可以消除错误,但我确实不想在
address\u id
上添加排序。是否可以不按地址id排序?

您可以在子查询中按地址id排序,然后在外部查询中按所需排序

SELECT * FROM 
    (SELECT DISTINCT ON (address_id) purchases.address_id, purchases.* 
    FROM "purchases" 
    WHERE "purchases"."product_id" = 1 ORDER BY address_id DESC ) 
ORDER BY purchased_at DESC
文件说:

DISTINCT ON(表达式[,…])仅保留给定表达式计算结果相等的每组行的第一行。[…]请注意,每个集合的“第一行”是不可预测的,除非使用ORDER BY来确保所需的行出现在第一行。[…]DISTINCT ON表达式必须与最左边的ORDER BY表达式匹配

因此,您必须将
地址\u id
添加到order by

或者,如果您正在查找包含每个
地址\u id
的最新购买产品的整行,以及按
购买的\u at
排序的结果,则您正在尝试解决一个最大的每组N个问题,该问题可通过以下方法解决:

适用于大多数DBMS的通用解决方案:

SELECT t1.* FROM purchases t1
JOIN (
    SELECT address_id, max(purchased_at) max_purchased_at
    FROM purchases
    WHERE product_id = 1
    GROUP BY address_id
) t2
ON t1.address_id = t2.address_id AND t1.purchased_at = t2.max_purchased_at
ORDER BY t1.purchased_at DESC
基于@hkf的答案,一个更面向PostgreSQL的解决方案:

SELECT * FROM (
  SELECT DISTINCT ON (address_id) *
  FROM purchases 
  WHERE product_id = 1
  ORDER BY address_id, purchased_at DESC
) t
ORDER BY purchased_at DESC

问题在此得到澄清、扩展和解决:

A子查询可以解决它:

SELECT *
FROM  (
    SELECT DISTINCT ON (address_id) *
    FROM   purchases
    WHERE  product_id = 1
    ) p
ORDER  BY purchased_at DESC;
排序依据
中的前导表达式必须与上的不同列一致,因此不能按同一
选择
中的不同列排序

如果要从每个集合中选取特定行,则仅在子查询中使用附加的
ORDER BY

SELECT *
FROM  (
    SELECT DISTINCT ON (address_id) *
    FROM   purchases
    WHERE  product_id = 1
    ORDER  BY address_id, purchased_at DESC  -- get "latest" row per address_id
    ) p
ORDER  BY purchased_at DESC;
如果在购买的
可以是
NULL
,请使用
DESC NULLS LAST
-并匹配您的索引以获得最佳性能。见:

相关,有更多解释:


窗口功能可一次性解决以下问题:

SELECT DISTINCT ON (address_id) 
   LAST_VALUE(purchases.address_id) OVER wnd AS address_id
FROM "purchases"
WHERE "purchases"."product_id" = 1
WINDOW wnd AS (
   PARTITION BY address_id ORDER BY purchases.purchased_at DESC
   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
对于任何使用它的人来说,这对我很有用

from app import db
from app.models import Purchases
from sqlalchemy.orm import aliased
from sqlalchemy import desc

stmt = Purchases.query.distinct(Purchases.address_id).subquery('purchases')
alias = aliased(Purchases, stmt)
distinct = db.session.query(alias)
distinct.order_by(desc(alias.purchased_at))

您也可以通过使用GROUPBY子句来实现这一点

   SELECT purchases.address_id, purchases.* FROM "purchases"
    WHERE "purchases"."product_id" = 1 GROUP BY address_id,
purchases.purchased_at ORDER purchases.purchased_at DESC

也可以使用以下查询和其他答案来解决此问题

WITH purchase_data AS (
        SELECT address_id, purchased_at, product_id,
                row_number() OVER (PARTITION BY address_id ORDER BY purchased_at DESC) AS row_number
        FROM purchases
        WHERE product_id = 1)
SELECT address_id, purchased_at, product_id
FROM purchase_data where row_number = 1


您的订单条款已在非地址处购买了\ u id。您能否澄清您的问题。我的订单已购买,因为我需要它,但postgres也要求提供地址(请参阅错误消息)。此处已完全回答-感谢个人,我认为要求DISTINCT ON匹配订单是非常可疑的,因为有各种不同的合法用例。postgresql.uservoice上有一篇文章试图为那些有类似感受的人改变这一点。得到了完全相同的问题,面临着同样的限制。目前,我已经将它分解成一个子查询,然后进行排序,但它感觉脏兮兮的。但这将比仅仅一个查询慢,不是吗?非常轻微地是的。虽然由于您有一个purchases.*在原始的
select
,但我不认为这是生产代码?我要补充的是,对于较新版本的postgres,您需要别名子查询。例如:选择*FROM(在(address_id)purchases.address_id,purchases.*FROM“purchases”,其中“purchases”。“product_id”=1 ORDER BY address_id DESC)作为tmp ORDER BY tmp.purchased_at DESC这将返回
address_id
两次(无需)。许多客户端都有重复列名的问题<代码>按地址排序\u id DESC
毫无意义且具有误导性。它在这个查询中没有任何用处。结果是从具有相同的
地址\u id
的每组行中任意选取,而不是从
购买的最新
行中选取。这个模棱两可的问题并没有明确要求这样做,但这几乎可以肯定是OP的意图。简而言之:不要使用此查询。我贴了一些有解释的备选方案。为我工作。回答得很好。它很有效,但给出了错误的顺序。这就是为什么我想去掉address\u id,以便条款说明清楚:你不能这样做,因为所选的行是不可预测的,但可能有另一种方法可以为disticnt地址选择最新的购买?问题的精神很清楚。不需要挑剔语义。令人遗憾的是,被接受和投票最多的答案无助于解决问题。下面是一篇postgresql.uservoice帖子,试图为那些认为这是一个有问题的限制的人解除这一限制。如果有人解释查询,那就太好了。@Gajus:简短解释:它不起作用,只返回不同的
地址\u id
。不过,这一原则可能会奏效。相关示例:或。但是对于手头的问题,有更短和/或更快的查询。这是不正确的(除非
purchases
只有两列
address\u id
purchased\u at
)。由于
groupby
,您需要使用聚合函数来获取未用于分组的每个列的值,因此这些值都将来自组的不同行,除非您进行了难看且低效的操作。这只能通过使用窗口函数而不是
分组依据来解决。如果没有匹配的
排序依据,则不能在
上使用
DISTINCT ON
。第一个查询要求在子查询中有一个
按地址排序\u id
。@AristolePagaltzis:但是您可以。无论你从哪里得到的,都是不正确的。您可以在同一查询中使用
DISTINCT ON
,而不使用
ORDER BY
。在本例中,您可以从
DISTINCT ON
子句定义的每组对等点中获得任意一行。请尝试或按照上面的链接查看详细信息和手册链接<在同一查询中(相同的
选择
)的code>orderby
)不能与
上的DISTINCT不一致。我也解释过了,你说得对。我对文档b中的“不可预测的,除非使用了
ORDER BY
”注释的含义视而不见