[sql] 다른 ORDER BY로 PostgreSQL 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 :: 오류 : 오류 : SELECT DISTINCT ON 표현식은 초기 ORDER BY 표현식과 일치해야합니다.

address_id첫 번째 ORDER BY표현식으로 추가 하면 오류가 발생하지 않지만 실제로 정렬을 추가하고 싶지 않습니다 address_id. 에 의해 주문하지 않고 할 수 address_id있습니까?



답변

설명서에 따르면 :

DISTINCT ON (expression [, …])은 주어진 표현식이 동일한 것으로 평가되는 각 행 세트의 첫 번째 행만 유지합니다. […] ORDER BY를 사용하여 원하는 행을 먼저 표시하지 않으면 각 세트의 “첫 번째 행”을 예측할 수 없습니다. […] DISTINCT ON 표현식은 가장 왼쪽의 ORDER BY 표현식과 일치해야합니다.

공식 문서

따라서 address_id주문 을에 추가해야합니다 .

또는 각 제품에 대해 가장 최근에 구매 한 제품이 포함 된 전체 행을 찾고 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

문제를 명확하게 설명하고 확장하고 해결했습니다. 일부 열별로 정렬되고 다른 열에서 구별되는 행 선택


답변

하위 쿼리에서 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


답변

하위 쿼리 를 해결할 수 있습니다 :

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. 그러나 사용하려는 경우 색인과 일치해야합니다. 보다:

자세한 설명과 함께 관련 :


답변

창 함수는 한 번에 해결 할 수 있습니다.

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


답변