不同的顺序

我想运行这个查询:

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

但是我得到了这个错误:

SELECT DISTINCT ON表达式必须匹配表达式的初始顺序

添加address_id作为第一个ORDER BY表达式可以消除错误,但我真的不想在address_id上添加排序。是否可以不通过address_id进行排序?

295512 次浏览

你可以在子查询中根据address_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表达式。

正式文档 .

所以你必须将address_id添加到by的顺序中。

或者,如果你正在寻找包含每个address_id最近购买的产品的整行,并且结果按purchased_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

问题澄清,扩展和解决在这里:选择按某列排序且在另一列上不同的行

子查询可以解决这个问题:

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

ORDER BY中的前导表达式必须与DISTINCT ON中的列一致,因此不能在同一个SELECT中按不同的列排序。

如果你想从每个集合中选择一个特定的行,只在子查询中使用额外的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;

如果purchased_at可以是NULL,则使用DESC NULLS LAST -并匹配索引以获得最佳性能。看到的:

相关,有更多解释:

Window函数可以一次性解决这个问题:

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)

对于任何使用Flask-SQLAlchemy的人来说,这对我来说都有效

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))

你也可以通过使用group by子句来做到这一点

   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