SELECT * FROM orders ORDER BY 1, 2 DESC;
이 문장에서 DESC 는 두 번째 정렬 키에만 걸린다. 첫 번째 키는 방향을 적지 않았으므로 기본값인 ASC 다. 결과는 1번 컬럼 오름차순, 그 안에서 2번 컬럼 내림차순이 된다.
둘 다 내림차순으로 하려면 각각 적는다.
SELECT * FROM orders ORDER BY 1 DESC, 2 DESC;
GROUP BY 나 PARTITION BY 와 달리 ORDER BY 는 키마다 방향과 NULL 처리를 따로 갖는다. 한 번만 적으면 전체에 걸린다고 생각하기 쉬운데, 그렇게 동작하는 DBMS 는 없다. 집계 결과를 정렬해 상위 N건을 뽑는 쿼리에서 이 실수가 나면 결과가 통째로 뒤바뀌므로, 오류 없이 틀린 답이 나온다.
ORDER BY 1 은 SELECT 목록의 첫 번째 항목을 가리킨다. 짧아서 편하지만 SELECT 목록이 바뀌면 조용히 다른 컬럼을 정렬하게 된다.
-- 처음
SELECT order_date, customer_id, amount FROM orders ORDER BY 1 DESC;
-- 컬럼 하나를 앞에 끼워 넣었다. 이제 1번은 region 이다
SELECT region, order_date, customer_id, amount FROM orders ORDER BY 1 DESC;
리뷰에서 잡히지 않는 종류의 변경이다. 운영에 남기는 쿼리는 컬럼명이나 별칭으로 적는다.
SELECT order_date, customer_id, amount
FROM orders
ORDER BY order_date DESC, customer_id;
SELECT * 와 서수를 같이 쓰면 더 위험하다. 테이블에 컬럼이 추가되거나 순서가 바뀌면 정렬 기준이 따라 움직인다.
서수 표기는 임시 조회나 UNION 결과처럼 별칭을 붙이기 어려운 자리에서만 쓴다. UNION 의 ORDER BY 는 전체 결과에 걸리며, 첫 번째 SELECT 의 컬럼명 또는 서수만 쓸 수 있다.
정렬 방향을 맞춰도 NULL 이 앞에 오는지 뒤에 오는지는 DBMS 마다 다르다.
| DBMS | 기본 동작 |
|---|---|
| PostgreSQL · Oracle | ASC 에서 NULL 이 뒤, DESC 에서 NULL 이 앞 |
| MySQL · MariaDB | ASC 에서 NULL 이 앞, DESC 에서 NULL 이 뒤 |
이식성이 필요하면 명시한다. PostgreSQL · Oracle · 대부분의 분산 SQL 엔진이 지원한다.
SELECT * FROM orders ORDER BY shipped_at DESC NULLS LAST;
MySQL 계열은 이 구문이 없으므로 식으로 대신한다.
SELECT * FROM orders ORDER BY (shipped_at IS NULL), shipped_at DESC;