0Pricing
SQL Academy · 강의

PostgreSQL DISTINCT ON

그룹마다 하나의 행을 선택합니다.

PostgreSQL DISTINCT ON은(는) CoddyKit의 무료 SQL Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 SQL Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

DISTINCT ON이란?

PostgreSQL은 표준 DISTINCT 키워드의 강력한 확장 기능인 DISTINCT ON을 제공합니다. 일반적인 DISTINCT는 완전히 중복된 행을 제거하는 반면, DISTINCT ON을 사용하면 선택한 하나 이상의 열을 기준으로 그룹별로 정확히 한 행을 선택할 수 있습니다.

이렇게 생각해 보세요. ‘이 열의 각 고유 값에 대해 행 하나를 주세요.’ 이는 고객별 최신 주문, 학생별 최고 점수 또는 범주별 첫 이벤트를 찾을 때 매우 유용합니다.

기본 DISTINCT ON 구문

구문에서는 DISTINCT ON (column)을 SELECT 바로 뒤에 배치합니다. 괄호 안의 열이 그룹을 정의하며 PostgreSQL은 해당 열의 각 고유 값에 대해 한 행을 반환합니다.

아래 예에서는 orders 테이블에서 각 customer_id별로 한 행을 반환합니다. PostgreSQL은 뒤따르는 ORDER BY 절을 기준으로 반환할 행을 선택합니다.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

예제 테이블 설정하기

간단한 orders 테이블을 만들고 몇 개의 샘플 행을 삽입하여 DISTINCT ON을 실제로 사용해 보겠습니다. 고객 세 명이 있으며, 각 고객에게는 서로 다른 날짜의 주문이 여러 건 있습니다.

CREATE TABLE orders (
  order_id      SERIAL PRIMARY KEY,
  customer_id   INT,
  order_date    DATE,
  total_amount  NUMERIC(10, 2)
);

INSERT INTO orders (customer_id, order_date, total_amount) VALUES
  (1, '2024-01-05', 120.00),
  (1, '2024-03-12', 85.50),
  (1, '2024-06-20', 200.00),
  (2, '2024-02-14', 45.00),
  (2, '2024-05-30', 310.00),
  (3, '2024-04-01', 75.00);

고객별 최신 주문

매우 흔한 활용 사례는 고객별 가장 최근 주문을 찾는 것입니다. 각 customer_id 그룹 안에서 order_date DESC로 정렬하면 DISTINCT ON이 가장 최신 날짜의 행을 선택합니다.

ORDER BY 절은 DISTINCT ON에 나열된 동일한 열로 시작해야 합니다. 이는 PostgreSQL의 요구 사항입니다.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

고객별 가장 이른 주문

고객별 첫 번째(가장 오래된) 주문을 대신 가져오려면 정렬 방향을 ASC로 바꾸기만 하면 됩니다. 유일한 차이는 각 그룹 내 행의 순서입니다. DISTINCT ON은 정렬 후 항상 첫 번째 행을 선택합니다.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
ORDER BY customer_id, order_date ASC;

ORDER BY 규칙

중요한 규칙: DISTINCT ON (col)을 사용할 때 ORDER BY 절은 반드시 DISTINCT ON 안에 나열된 동일한 열로 시작해야 합니다. 그렇지 않으면 PostgreSQL이 오류를 발생시킵니다.

그룹화 열 다음에는 각 그룹에서 선택할 행을 제어하도록 원하는 추가 정렬 기준을 넣을 수 있습니다.

-- Correct: ORDER BY starts with the DISTINCT ON column
SELECT DISTINCT ON (customer_id)
  customer_id, order_date, total_amount
FROM orders
ORDER BY customer_id, total_amount DESC;

-- This would cause an error:
-- ORDER BY order_date DESC  (missing customer_id at the start)

학생별 최고 점수

또 다른 실용적인 예로 test_scores 테이블을 사용해 보겠습니다. 각 학생이 지금까지 받은 가장 높은 점수를 찾으려고 합니다. 각 학생 그룹 내에서 score DESC로 정렬하면 DISTINCT ON이 학생별로 점수가 가장 높은 행만 반환합니다.

CREATE TABLE test_scores (
  id         SERIAL PRIMARY KEY,
  student_id INT,
  subject    VARCHAR(50),
  score      INT,
  taken_on   DATE
);

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Math',    92, '2024-02-10'),
  (101, 'Math',    78, '2024-04-15'),
  (102, 'Math',    85, '2024-02-10'),
  (102, 'Math',    91, '2024-04-15'),
  (103, 'Math',    67, '2024-02-10');

SELECT DISTINCT ON (student_id)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, score DESC;

여러 열과 함께 사용하는 DISTINCT ON

DISTINCT ON 안에 여러 열을 나열하면 둘 이상의 열로 그룹화할 수 있습니다. 그러면 해당 열들의 각 고유한 조합마다 한 행이 반환됩니다.

아래 예에서는 학생별 과목별 최고 점수를 선택하며, 각 (학생, 과목) 쌍을 별도의 그룹으로 취급합니다.

INSERT INTO test_scores (student_id, subject, score, taken_on) VALUES
  (101, 'Science', 88, '2024-03-01'),
  (101, 'Science', 95, '2024-05-20'),
  (102, 'Science', 72, '2024-03-01');

SELECT DISTINCT ON (student_id, subject)
  student_id, subject, score, taken_on
FROM test_scores
ORDER BY student_id, subject, score DESC;

WHERE로 필터링하기

DISTINCT ON은 WHERE 절과 자연스럽게 함께 작동합니다. 필터가 먼저 적용된 다음 DISTINCT ON이 필터링된 결과에서 그룹별로 한 행을 선택합니다.

여기서는 100을 초과하는 주문만 대상으로 고객별 가장 최근 주문을 찾습니다.

SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  order_date,
  total_amount
FROM orders
WHERE total_amount > 100
ORDER BY customer_id, order_date DESC;

DISTINCT ON과 GROUP BY 비교

DISTINCT ON과 GROUP BY는 모두 그룹별로 한 행을 만들 수 있지만 용도가 다릅니다:

  • GROUP BY는 행을 하나로 합치며, 그룹화되지 않은 열에는 SUM, MAX 등의 집계 함수가 필요합니다.
  • DISTINCT ON은 실제로 존재하는 행을 유지하므로 모든 열을 집계 없이 사용할 수 있습니다.

집계된 값이 필요할 때는 GROUP BY를 사용하세요. 각 그룹에서 특정 행의 전체 데이터가 필요할 때는 DISTINCT ON을 사용하세요.

-- GROUP BY: only aggregated columns allowed
SELECT customer_id, MAX(order_date) AS latest_date
FROM orders
GROUP BY customer_id;

-- DISTINCT ON: returns the whole row for that latest date
SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

하위 쿼리에서 DISTINCT ON 사용하기

때로는 DISTINCT ON 결과에 추가로 필터링하거나 정렬해야 합니다. 바깥쪽 ORDER BY는 그룹화 열과 연결되어 있으므로, 쿼리를 하위 쿼리(또는 CTE)로 감싸 최종 출력에 다른 정렬을 적용할 수 있습니다.

이 예에서는 먼저 고객별 최신 주문을 선택한 다음 최종 결과를 total_amount 내림차순으로 정렬합니다.

SELECT *
FROM (
  SELECT DISTINCT ON (customer_id)
    customer_id,
    order_id,
    order_date,
    total_amount
  FROM orders
  ORDER BY customer_id, order_date DESC
) AS latest_orders
ORDER BY total_amount DESC;

빠른 확인

DISTINCT ON에 대한 이해도를 확인해 보겠습니다. 아래 쿼리를 주의 깊게 읽고 어떤 결과를 반환하는지 가장 잘 설명하는 답을 선택하세요.

SELECT DISTINCT ON (department_id) department_id, employee_name, salary FROM employees ORDER BY department_id, salary DESC;

강의 요약

잘하셨습니다! PostgreSQL DISTINCT ON에 대해 배운 내용을 정리해 보겠습니다:

  • DISTINCT ON (col)은 지정한 열의 각 고유 값마다 정확히 한 행을 반환합니다.
  • ORDER BY 절은 반드시 시작해야 하는 열이 DISTINCT ON에 나열된 동일한 열이어야 합니다. 이는 각 그룹에서 선택되는 행을 결정합니다.
  • 여러 열을 사용할 수 있습니다. DISTINCT ON (col1, col2)는 두 열의 조합으로 그룹화합니다.
  • GROUP BY와 달리 DISTINCT ON은 원래의 모든 열을 포함한 실제 행을 반환하므로 집계가 필요하지 않습니다.
  • 최종 출력을 다른 열로 정렬해야 할 때는 쿼리를 하위 쿼리로 감싸세요.

DISTINCT ON은 PostgreSQL에만 있는 기능이며 ‘그룹별로 한 행 선택’ 문제를 해결하는 가장 우아한 방법 중 하나입니다.

자주 묻는 질문

“PostgreSQL DISTINCT ON” 강의는 무료인가요?

네 — “PostgreSQL DISTINCT ON” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 SQL Academy 강의 전체를 잠금 해제할 수 있습니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“PostgreSQL DISTINCT ON”에서 뭘 배우나요?

그룹마다 하나의 행을 선택합니다. 브라우저에서 직접 실행하는 실습 코드로 SQL Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

SQL Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 SQL Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“PostgreSQL DISTINCT ON” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 SQL Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 SQL Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. SELECT DISTINCT 기초
  2. 여러 열에 DISTINCT 적용하기
  3. PostgreSQL DISTINCT ON
  4. 고유한 값 세기
← SQL Academy(으)로 돌아가기