현재 선택한 SQL 과정

SQLD 이론 학습

이론 목록으로 돌아가기

ORDER BY와 Top-N

다중 정렬 기준·NULL 배치·ROW_NUMBER와 FETCH를 이용한 안정적인 Top-N을 이해한다.

예상 읽기 6

핵심 요약

다중 정렬 기준·NULL 배치·ROW_NUMBER와 FETCH를 이용한 안정적인 Top-N을 이해한다.

핵심 질문

  1. ORDER BY와 Top-N에서 반드시 구분해야 할 개념과 결과 규칙은 무엇인가?
  2. 0건·1건·여러 건과 NULL·동점·중복 데이터에서 결과가 어떻게 달라지는가?
  3. 비슷해 보이는 문법과 결과가 같아지는 조건, 달라지는 조건은 무엇인가?
  4. 작은 샘플 데이터를 이용해 결과를 실수 없이 예측하는 순서는 무엇인가?

학습 목표

  • ASC·DESC와 NULL 정렬 위치를 명시한다.
  • Top-N과 페이지 조회에 결정적인 정렬 기준이 필요한 이유를 설명한다.

개념 지도

CODE코드 영역 안에서 좌우로 이동할 수 있습니다.
결과 행 생성 → 정렬 기준·방향·NULL 위치 → 동점 Tie-breaker → 행 제한

핵심 내용

관계형 결과는 ORDER BY가 없으면 순서가 보장되지 않는다. 여러 기준을 왼쪽부터 적용하며 각 기준마다 ASC·DESC를 지정할 수 있다.

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT empno, ename, sal
FROM emp
ORDER BY sal DESC, empno ASC;

동점이 존재할 수 있는 sal만 정렬하면 실행마다 동점 행 순서가 달라질 수 있다. PK 같은 유일한 컬럼을 마지막 정렬 기준으로 추가하면 안정적이다. Oracle은 NULLS FIRST, NULLS LAST로 NULL 위치를 명시할 수 있다.

상위 N건은 최신 문법의 FETCH FIRST 또는 분석 함수로 표현한다.

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT empno, sal
FROM emp
ORDER BY sal DESC, empno
FETCH FIRST 5 ROWS ONLY;

ROWNUM을 사용한다면 정렬보다 먼저 부여될 수 있으므로 정렬한 인라인 뷰 바깥에서 제한하는 구조를 이해해야 한다.

흔한 오해와 주의점

  • ORDER BY의 숫자는 SELECT 목록의 위치를 뜻할 수 있지만 유지보수성이 낮다.
  • Top-N에서 동점 처리 여부와 정확히 N행 반환 여부를 구분한다.
  • 페이지 번호가 깊어질수록 OFFSET 방식은 앞 행을 계속 처리해야 할 수 있다.

문항 풀이 보강: Top-N 문법별 실행 순서

Oracle ROWNUM

ROWNUM은 같은 쿼리 블록의 ORDER BY보다 먼저 붙을 수 있다. 먼저 정렬한 뒤 바깥에서 제한한다.

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT *
FROM (
  SELECT team_name, wins
  FROM team_score
  ORDER BY wins DESC
)
WHERE ROWNUM <= 3;

동점까지 포함하려면 RANKDENSE_RANK, 또는 DBMS가 지원하는 FETCH FIRST 3 ROWS WITH TIES를 사용한다.

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT *
FROM team_score
ORDER BY wins DESC
FETCH FIRST 3 ROWS WITH TIES;

SQL Server의 TOP (3) WITH TIES도 ORDER BY의 마지막 경계값과 같은 행을 함께 반환한다.

순위 함수 선택

  • 정확히 N행이 필요하면 결정적 ORDER BY와 ROW_NUMBER.
  • 동점 다음 순위를 건너뛰는 경기 순위면 RANK.
  • 동점 뒤에도 연속 순위면 DENSE_RANK.

정렬 기준이 유일하지 않으면 같은 점수의 행 순서는 달라질 수 있으므로 정확히 N행을 요구할 때는 PK 같은 보조 정렬키를 추가한다.

결정적인 정렬 만들기

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT order_id, created_at, amount
FROM   orders
ORDER  BY created_at DESC, order_id DESC;

created_at만 정렬하면 같은 시각의 행 순서는 결정되지 않는다. PK인 order_id를 Tie-breaker로 추가해야 반복 실행과 Pagination에서 안정적인 순서를 얻는다.

FETCH FIRST와 WITH TIES

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
-- 정확히 10행 이하
FETCH FIRST 10 ROWS ONLY

-- 10번째 행과 정렬값이 같은 동점까지 포함
FETCH FIRST 10 ROWS WITH TIES

WITH TIES는 반환 행 수가 10보다 많을 수 있다. 동점 기준은 전체 ORDER BY 표현식이므로 PK까지 포함하면 사실상 Tie가 없어질 수 있다.

ROWNUM의 올바른 위치

SQL코드 영역 안에서 좌우로 이동할 수 있습니다.
SELECT *
FROM (
  SELECT order_id, amount
  FROM orders
  ORDER BY amount DESC, order_id
)
WHERE ROWNUM <= 10;

ROWNUM을 정렬과 같은 Query Block에 두면 먼저 선택된 행을 정렬할 수 있다. Oracle 12c 이상의 Row Limiting Clause를 사용하더라도 동점 행의 순서를 결정할 추가 정렬 기준이 필요하다.

NULL 정렬

Oracle의 기본 NULL 위치는 정렬 방향에 따라 달라질 수 있으므로 업무 요구가 있으면 NULLS FIRST 또는 NULLS LAST를 명시한다. SQL 결과 순서는 ORDER BY 없이는 보장되지 않는다.


결과를 검증하는 순서

  1. 각 Query Block이 만드는 한 행의 의미를 먼저 적습니다.
  2. 조건을 적용하기 전 원본 행과 적용 후 남는 행을 작은 표로 그립니다.
  3. NULL 비교가 TRUE, FALSE, UNKNOWN 중 무엇인지 구분합니다.
  4. 중복 제거, 그룹화, 정렬과 행 제한이 적용되는 순서를 확인합니다.
  5. 데이터가 0건·1건·여러 건일 때도 같은 규칙이 성립하는지 검증합니다.

실무와 시험에서 함께 확인할 항목

  • ORDER BY가 없다면 결과 순서를 가정하지 않습니다.
  • 문자열·숫자·날짜 비교에서는 데이터 타입과 명시적 형변환을 확인합니다.
  • 같은 결과처럼 보이는 SQL도 NULL과 중복이 있을 때 달라질 수 있습니다.
  • 문법을 외우기 전에 샘플 데이터 3~5행으로 결과를 직접 계산합니다.

마지막 점검

  • 작성 순서가 아니라 SQL의 논리적 처리 순서로 결과를 계산합니다.
  • NULL을 0이나 빈 값과 같은 것으로 취급하지 않습니다.
  • ORDER BY가 없는 결과 순서와 DISTINCT 없는 중복 제거를 가정하지 않습니다.
  • 비슷한 문법은 0건·다건·NULL 데이터를 넣어 결과가 정말 같은지 확인합니다.

복습 문제

  1. 동점이 있는 결과에 PK 정렬을 추가하는 이유는?
  2. ROWNUM과 ORDER BY를 같은 단계에서 단순 결합하면 생길 수 있는 문제는?
  3. 샘플 데이터 3행으로 결과를 직접 계산할 수 있는가?
  4. NULL이 포함될 때 결과가 달라지는 지점은 어디인가?