본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
  • 상위 문서: SQL
ORDER BY Clause
조회 결과 행을 지정한 기준에 따라 정렬하는 SQL 절

ORDER BY 절은 SELECT 문이 돌려주는 결과 행의 순서를 정한다. ORDER BY가 없으면 결과 순서는 보장되지 않는다. 테이블에 넣은 순서나 인덱스 순서로 나오는 것처럼 보여도 실행 계획이 바뀌면 달라질 수 있다. ORDER BY는 SELECT 문의 맨 끝에 쓰며, 논리적 처리 순서에서도 가장 마지막에 실행된다.

B_EMP

사원번호 이름 부서번호 관리자번호 급여 입사일 커미션
1001 김대표 10 NULL 9000 2015-01-05 NULL
1002 이부장 20 1001 6000 2017-03-15 NULL
1003 박과장 20 1002 4500 2019-07-01 NULL
1004 최대리 30 1001 4000 2020-11-20 500
1005 정사원 30 1004 3000 2022-02-28 0
1006 한신입 NULL 1002 2500 2024-08-01 NULL
SELECT 칼럼 목록
FROM 테이블
[WHERE 조건]
[GROUP BY 칼럼] [HAVING 조건]
ORDER BY 기준1 [ASC | DESC] [NULLS FIRST | NULLS LAST], 기준2 [ASC | DESC] ...;
  • ASC는 오름차순(작은 값부터)이며 기본값이다. DESC는 내림차순이다.
  • 숫자는 작은 수, 날짜는 이른 날짜, 문자는 사전 순으로 앞선 값이 오름차순에서 먼저 나온다.

정렬 기준 지정 방법

편집 원본 편집
방법 예 설명
칼럼명 ORDER BY 급여 DESC 가장 일반적인 방법
별칭 SELECT 급여*12 AS 연봉 ... ORDER BY 연봉 DESC SELECT 절에서 붙인 별칭을 쓸 수 있다.
위치 번호 SELECT 이름, 급여 ... ORDER BY 2 DESC, 1 SELECT 목록의 순번. 목록에 없는 번호를 쓰면 ORA-01785 오류
표현식 ORDER BY CASE 부서번호 WHEN 30 THEN 1 ... END 함수나 CASE 등의 계산 결과로 정렬
  • 칼럼명, 별칭, 위치 번호를 한 ORDER BY 안에 섞어 쓸 수 있다.

여러 칼럼 정렬

편집 원본 편집

첫 번째 기준 값이 같은 행끼리 두 번째 기준으로 정렬한다. ASC와 DESC는 칼럼마다 따로 지정한다.

SELECT 이름, 부서번호, 급여 FROM B_EMP
ORDER BY 부서번호, 급여 DESC;      -- 부서번호는 ASC(생략), 급여는 DESC
이름 부서번호 급여
김대표 10 9000
이부장 20 6000
박과장 20 4500
최대리 30 4000
정사원 30 3000
한신입 NULL 2500

NULL의 정렬 위치

편집 원본 편집

Oracle은 정렬할 때 NULL을 가장 큰 값으로 취급한다. 그래서 ASC에서는 맨 뒤, DESC에서는 맨 앞에 온다. SQL Server는 반대로 NULL을 가장 작은 값으로 취급한다.

DBMS ASC DESC
Oracle NULL이 마지막 NULL이 처음
SQL Server NULL이 처음 NULL이 마지막

Oracle은 NULLS FIRST, NULLS LAST로 NULL 위치를 직접 정할 수 있다.

SELECT 이름, 부서번호 FROM B_EMP ORDER BY 부서번호 DESC, 사원번호;              -- (1)
SELECT 이름, 부서번호 FROM B_EMP ORDER BY 부서번호 DESC NULLS LAST, 사원번호;   -- (2)
SELECT 이름, 부서번호 FROM B_EMP ORDER BY 부서번호 ASC NULLS FIRST, 사원번호;   -- (3)
순서 (1) DESC (2) DESC NULLS LAST (3) ASC NULLS FIRST
1 한신입(NULL) 최대리(30) 한신입(NULL)
2 최대리(30) 정사원(30) 김대표(10)
3 정사원(30) 이부장(20) 이부장(20)
4 이부장(20) 박과장(20) 박과장(20)
5 박과장(20) 김대표(10) 최대리(30)
6 김대표(10) 한신입(NULL) 정사원(30)
  • SQL Server는 NULLS FIRST·NULLS LAST 구문이 없어 ORDER BY CASE WHEN 칼럼 IS NULL THEN 1 ELSE 0 END, 칼럼처럼 CASE로 처리한다.

SELECT 목록에 없는 칼럼으로 정렬

편집 원본 편집

일반 SELECT 문에서는 SELECT 목록에 없는 칼럼으로도 정렬할 수 있다. 그러나 GROUP BY나 DISTINCT를 쓰면 정렬 기준이 제한된다. Oracle에서 실행한 결과는 다음과 같다.

쿼리 결과
SELECT 이름 FROM B_EMP ORDER BY 입사일 DESC 가능. 한신입, 정사원, 최대리, 박과장, 이부장, 김대표
SELECT SUM(급여) AS 합계 FROM B_EMP GROUP BY 부서번호 ORDER BY 부서번호 가능. GROUP BY 표현식은 SELECT 목록에 없어도 된다.
SELECT 부서번호, SUM(급여) FROM B_EMP GROUP BY 부서번호 ORDER BY MAX(급여) DESC 가능. 집계 함수로 정렬할 수 있다.
SELECT 부서번호, SUM(급여) FROM B_EMP GROUP BY 부서번호 ORDER BY 급여 ORA-00979 오류. 그룹으로 묶인 뒤에는 개별 급여 값이 없다.
SELECT DISTINCT 부서번호 FROM B_EMP ORDER BY 급여 ORA-01791(not a SELECTed expression) 오류. DISTINCT를 쓰면 SELECT 목록에 있는 것으로만 정렬할 수 있다.
  • ORA-00979의 메시지는 버전에 따라 다르다. 19c까지는 not a GROUP BY expression, 23ai 이후는 칼럼이 GROUP BY 절에 있거나 집계 함수에 쓰여야 한다는 문구로 나온다.

실행 순서와 별칭

편집 원본 편집

논리적 처리 순서는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY이다. ORDER BY는 SELECT 다음에 처리되므로 SELECT 절의 별칭을 쓸 수 있다. WHERE, GROUP BY, HAVING 절에서는 별칭을 쓸 수 없다(SQL WHERE 절).

SELECT 이름, 급여*12 AS 연봉 FROM B_EMP ORDER BY 연봉 DESC;
-- 김대표 108000, 이부장 72000, 박과장 54000, 최대리 48000, 정사원 36000, 한신입 30000

CASE를 이용한 사용자 정의 정렬

편집 원본 편집

값의 크기 순서가 아닌 업무상 순서로 정렬하려면 CASE로 순번을 만들어 정렬한다.

SELECT 이름, 부서번호 FROM B_EMP
ORDER BY CASE 부서번호 WHEN 30 THEN 1 WHEN 10 THEN 2 ELSE 3 END, 사원번호;
이름 부서번호
최대리 30
정사원 30
김대표 10
이부장 20
박과장 20
한신입 NULL

ROWNUM과 ORDER BY

편집 원본 편집

ROWNUM은 WHERE 절에서 행이 걸러질 때 붙고, ORDER BY는 그 뒤에 실행된다. 따라서 같은 쿼리 안에서 ROWNUM으로 자른 뒤 정렬하면 "급여가 낮은 3명"이 아니라 "먼저 읽힌 3명을 급여순으로 정렬한 것"이 된다.

-- (1) 잘못된 방법: 먼저 3행을 고른 뒤 정렬
SELECT 이름, 급여 FROM B_EMP WHERE ROWNUM <= 3 ORDER BY 급여;

-- (2) 올바른 방법: 인라인 뷰에서 정렬한 뒤 3행을 고른다
SELECT 이름, 급여 FROM (SELECT 이름, 급여 FROM B_EMP ORDER BY 급여) WHERE ROWNUM <= 3;
(1) 결과 (2) 결과
박과장 4500 한신입 2500
이부장 6000 정사원 3000
김대표 9000 최대리 4000
  • (1)의 결과는 테이블에서 행을 읽은 순서에 따라 달라질 수 있다. 자세한 내용은 Top N 쿼리에서 다룬다.

집합 연산자와 ORDER BY

편집 원본 편집

UNION, UNION ALL, INTERSECT, MINUS로 여러 SELECT를 합칠 때 ORDER BY는 맨 마지막 SELECT 뒤에 한 번만 쓰며, 전체 결과를 정렬한다(SQL 집합 연산자).

SELECT 이름 AS 성명 FROM B_EMP WHERE 부서번호 = 10
UNION ALL
SELECT 이름 FROM B_EMP WHERE 부서번호 = 30
ORDER BY 1 DESC;          -- 최대리, 정사원, 김대표
쿼리 결과
첫 SELECT 뒤에 ORDER BY를 쓰고 UNION ALL을 이어 씀 구문 오류. 26ai에서는 ORA-03048(UNION이 올 수 없는 위치)로 표시된다.
ORDER BY 1 DESC 또는 ORDER BY 성명 가능. 위치 번호나 첫 번째 SELECT의 칼럼명·별칭을 쓴다.
두 번째 SELECT의 별칭(ORDER BY 명) ORA-00904 오류
SELECT 목록에 없는 칼럼(ORDER BY 급여) ORA-00904 오류
  • Oracle은 NULL을 가장 큰 값으로 보아 ASC에서 마지막, DESC에서 처음에 둔다. SQL Server는 반대이다. NULLS FIRST·NULLS LAST로 바꿀 수 있다.
  • ORDER BY에는 칼럼명, 별칭, SELECT 목록 위치 번호를 쓸 수 있고 섞어 써도 된다. 목록 범위를 벗어난 번호는 오류이다.
  • SELECT 목록에 없는 칼럼으로 정렬: 일반 SELECT는 가능, GROUP BY 쿼리는 GROUP BY 표현식과 집계 함수만, DISTINCT 쿼리는 SELECT 목록 항목만 가능하다.
  • ORDER BY는 가장 마지막에 실행되므로 별칭을 쓸 수 있고, ROWNUM 조건보다 늦게 적용된다.
  • 집합 연산자를 쓰면 ORDER BY는 맨 끝에 한 번만, 첫 번째 SELECT의 칼럼명·별칭 또는 위치 번호로 쓴다.