[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