ORDER BY는 쿼리가 반환하는 행을 하나 이상의 컬럼이나 표현식 기준으로 오름차순 또는 내림차순 정렬해요. ORDER BY가 없으면 데이터베이스는 가장 빠른 순서대로 행을 반환해요. 예제는 PostgreSQL, MySQL, SQLite, SQL Server에서 모두 동작해요.
ORDER BY 사용법
ORDER BY는 쿼리 끝, WHERE, GROUP BY, HAVING 뒤에 넣어요. 그 뒤에 올 수 있는 건 LIMIT뿐이에요. 정렬 기준 컬럼을 나열하면 되고, DESC를 붙이지 않으면 각 컬럼은 오름차순으로 정렬돼요:
SELECT columns
FROM table_name
ORDER BY column1 [ASC | DESC], column2 [ASC | DESC];
-- Input: customers
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 1 | Olivia Hart | 2024-03-12
-- 2 | Marcus Lee | 2023-11-05
-- 3 | Zara Ahmed | 2024-01-27
-- 4 | Ben Carter | 2023-08-19
SELECT customer_id, name, signup_date
FROM customers
ORDER BY signup_date;
-- Output:
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 4 | Ben Carter | 2023-08-19
-- 2 | Marcus Lee | 2023-11-05
-- 3 | Zara Ahmed | 2024-01-27
-- 1 | Olivia Hart | 2024-03-12
SELECT customer_id, name, signup_date
FROM customers
ORDER BY signup_date DESC;
-- Output:
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 1 | Olivia Hart | 2024-03-12
-- 3 | Zara Ahmed | 2024-01-27
-- 2 | Marcus Lee | 2023-11-05
-- 4 | Ben Carter | 2023-08-19
알아 둘 규칙
-
DESC는 바로 앞의 컬럼에만 적용돼요.
ORDER BY author, published DESC는 저자를 A부터 Z 순으로 정렬한 뒤, 저자별 책을 최신순으로 정렬해요:
-- Input: books
-- title | author | published
-- --------------------+-----------------+----------
-- Emma | Jane Austen | 1815
-- Bleak House | Charles Dickens | 1853
-- Pride and Prejudice | Jane Austen | 1813
-- Hard Times | Charles Dickens | 1854
SELECT title, author, published
FROM books
ORDER BY author, published DESC;
-- Output:
-- title | author | published
-- --------------------+-----------------+----------
-- Hard Times | Charles Dickens | 1854
-- Bleak House | Charles Dickens | 1853
-- Emma | Jane Austen | 1815
-- Pride and Prejudice | Jane Austen | 1813
-
ORDER BY가 없으면 순서가 보장되지 않아요. 행이 삽입된 순서대로 나오는 경우가 많지만, 테이블이 커지거나 인덱스가 바뀌거나 쿼리가 병렬로 실행되면 달라져요.
LIMIT도 마찬가지예요. ORDER BY 없이 쓰면 데이터베이스가 먼저 읽은 행을 반환해요. - 값이 같은 행은 순서가 정해지지 않아요. ID 같은 고유 컬럼을 마지막 정렬 컬럼으로 추가하면 실행할 때마다 같은 순서가 나와요:
-- Input: customers
-- customer_id | name | signup_date
-- ------------+------------+------------
-- 3 | Mara Lind | 2024-01-15
-- 1 | Owen Price | 2024-01-10
-- 4 | Tariq Aziz | 2024-01-15
-- 2 | Lily Shore | 2024-01-15
-- The three 2024-01-15 rows can come back in any order
SELECT * FROM customers ORDER BY signup_date;
-- Output:
-- customer_id | name | signup_date
-- ------------+------------+------------
-- 1 | Owen Price | 2024-01-10
-- 3 | Mara Lind | 2024-01-15
-- 4 | Tariq Aziz | 2024-01-15
-- 2 | Lily Shore | 2024-01-15
-- customer_id breaks the tie
SELECT * FROM customers ORDER BY signup_date, customer_id;
-- Output:
-- customer_id | name | signup_date
-- ------------+------------+------------
-- 1 | Owen Price | 2024-01-10
-- 2 | Lily Shore | 2024-01-15
-- 3 | Mara Lind | 2024-01-15
-- 4 | Tariq Aziz | 2024-01-15
- NULL은 맨 앞에 정렬되지만, PostgreSQL은 맨 뒤에 둬요. 오름차순 기준이고, DESC를 쓰면 반대가 돼요:
-- Input: users
-- name | middle_name
-- -----------+------------
-- John Smith | Robert
-- Ana Lopez | NULL
-- Kim Young | Elise
SELECT name, middle_name
FROM users
ORDER BY middle_name;
-- Output:
-- name | middle_name
-- -----------+------------
-- Ana Lopez | NULL
-- Kim Young | Elise
-- John Smith | Robert
-- (PostgreSQL puts Ana Lopez last instead)
NULL의 위치를 직접 정하려면 아래의 NULLS FIRST와 NULLS LAST를 참고하세요.
다른 문법
컬럼 별칭이나 SELECT 목록에서의 컬럼 위치로도 정렬할 수 있어요. 별칭을 쓰면 표현식을 반복하지 않아도 돼요. 위치 번호는 더 짧지만 누군가 SELECT 목록을 수정하면 아무 경고 없이 잘못 동작해요:
-- Input: employees
-- name | monthly_salary
-- ---------+---------------
-- Ivy Chen | 5200
-- Max Dunn | 7600
-- Pia Roth | 4500
SELECT name, monthly_salary * 12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC; -- or ORDER BY 2 DESC
-- Output:
-- name | annual_salary
-- ---------+--------------
-- Max Dunn | 91200
-- Ivy Chen | 62400
-- Pia Roth | 54000
정렬 컬럼 뒤에 NULLS FIRST나 NULLS LAST를 붙이면 NULL의 위치를 지정할 수 있어요:
-- Input: the users table above
SELECT name, middle_name
FROM users
ORDER BY middle_name NULLS LAST;
-- MySQL and SQL Server don't support NULLS LAST. Sort on a CASE first instead:
-- ORDER BY CASE WHEN middle_name IS NULL THEN 1 ELSE 0 END, middle_name
-- Output:
-- name | middle_name
-- -----------+------------
-- Kim Young | Elise
-- John Smith | Robert
-- Ana Lopez | NULL
MySQL에는 나열한 순서대로 값을 정렬하는 FIELD()가 있어요. 다른 데이터베이스에서는 아래 우선순위로 작업 정렬하기처럼 CASE 표현식을 쓰세요:
-- Input: products
-- product_name | category
-- -------------+------------
-- Cookbook | Books
-- Raincoat | Clothing
-- Tablet | Electronics
-- Scarf | Clothing
-- MySQL
SELECT * FROM products
ORDER BY FIELD(category, 'Electronics', 'Clothing', 'Books');
-- Output:
-- product_name | category
-- -------------+------------
-- Tablet | Electronics
-- Raincoat | Clothing
-- Scarf | Clothing
-- Cookbook | Books
ORDER BY는 언제 사용하나요?
읽는 사람에게 행의 순서가 의미 있을 때는 언제든 ORDER BY를 쓰세요. 대부분의 용도는 다음 네 가지 중 하나에 해당해요.
목록을 일정한 순서로 보여주기
이름은 A부터 Z까지, 날짜는 오래된 순, ID는 순서대로. ORDER BY가 없으면 같은 쿼리라도 실행할 때마다 행 순서가 달라질 수 있고, 결과 페이지가 겹치거나 행이 빠질 수 있어요.
가장 큰 값이나 최신 값 찾기
내림차순으로 정렬해 가장 크거나 최신이거나 비싼 행을 앞에 두고, LIMIT을 더해 상위 몇 개만 남기세요. 베스트셀러, 최근 주문, 최고 점수 같은 경우예요.
여러 컬럼으로 정렬하기
첫 번째 정렬 컬럼에 같은 값이 있으면 다음 컬럼이 그 안에서 순서를 정해요. 부서 다음 급여, 학년 다음 점수, 상태 다음 날짜처럼요. 컬럼마다 정렬 방향을 따로 지정할 수 있어요.
계산한 값이나 사용자 지정 순서로 정렬하기
ORDER BY에는 컬럼뿐 아니라 어떤 표현식이든 쓸 수 있어요. 두 컬럼으로 계산한 합계, 이름의 길이, 또는 High, Medium, Low처럼 알파벳순으로는 얻을 수 없는 순서를 만드는 CASE 표현식도 가능해요.
ORDER BY 실전 예제
고객 목록 페이지 나누기
ORDER BY를 LIMIT, OFFSET과 함께 쓰면 한 번에 한 페이지씩 반환해요. 고객 세 명이 같은 날 가입했기 때문에 customer_id로 동점을 가려요. 이게 없으면 데이터베이스가 같은 고객을 두 페이지에 모두 넣고 다른 고객을 빠뜨릴 수 있어요:
-- Input: customers
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 1 | Nina Brandt | 2024-02-14
-- 2 | Theo Walsh | 2023-09-30
-- 3 | Iris Novak | 2024-02-14
-- 4 | Felix Moore | 2024-02-14
-- 5 | June Park | 2024-03-22
-- Page 1
SELECT customer_id, name, signup_date
FROM customers
ORDER BY signup_date, customer_id
LIMIT 2 OFFSET 0;
-- Output:
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 2 | Theo Walsh | 2023-09-30
-- 1 | Nina Brandt | 2024-02-14
-- Page 2
SELECT customer_id, name, signup_date
FROM customers
ORDER BY signup_date, customer_id
LIMIT 2 OFFSET 2;
-- SQL Server has no LIMIT: use OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY
-- Output:
-- customer_id | name | signup_date
-- ------------+-------------+------------
-- 3 | Iris Novak | 2024-02-14
-- 4 | Felix Moore | 2024-02-14
리더보드 상위 3위 보여주기
점수를 높은 순으로 정렬하고 처음 세 개만 남겨요:
-- Input: players
-- username | score
-- ----------+------
-- quokka42 | 1870
-- nightowl | 2310
-- pixelpete | 1525
-- zara_k | 2045
-- bytebard | 1990
SELECT username, score
FROM players
ORDER BY score DESC
LIMIT 3;
-- SQL Server has no LIMIT: write SELECT TOP 3 username, score instead
-- Output:
-- username | score
-- ---------+------
-- nightowl | 2310
-- zara_k | 2045
-- bytebard | 1990
상태, 금액, 날짜별 주문 보고서 만들기
상태는 알파벳순으로 정렬돼요. 각 상태 안에서는 금액이 큰 주문이 먼저 나오고, 금액이 같으면 최신 주문이 먼저 나와요:
-- Input: orders
-- order_id | status | order_value | order_date
-- ---------+------------+-------------+-----------
-- 1001 | Shipped | 120.00 | 2024-03-02
-- 1002 | Delivered | 75.50 | 2024-02-20
-- 1003 | Shipped | 120.00 | 2024-03-05
-- 1004 | Processing | 42.00 | 2024-03-06
-- 1005 | Delivered | 210.00 | 2024-02-28
SELECT order_id, status, order_value, order_date
FROM orders
ORDER BY status ASC, order_value DESC, order_date DESC;
-- Output:
-- order_id | status | order_value | order_date
-- ---------+------------+-------------+-----------
-- 1005 | Delivered | 210.00 | 2024-02-28
-- 1002 | Delivered | 75.50 | 2024-02-20
-- 1004 | Processing | 42.00 | 2024-03-06
-- 1003 | Shipped | 120.00 | 2024-03-05
-- 1001 | Shipped | 120.00 | 2024-03-02
우선순위로 작업 정렬하기
알파벳순으로 정렬하면 High, Low, Medium이 돼요. CASE 표현식으로 각 우선순위를 정렬용 숫자로 바꿔요. 그 외의 값(여기서는 NULL)은 4가 되어 맨 뒤로 가고, 같은 우선순위 안에서는 마감일로 정렬해요:
-- Input: tasks
-- task_name | priority | due_date
-- ---------------+----------+-----------
-- Update docs | Low | 2024-06-03
-- Fix login bug | High | 2024-06-10
-- Plan offsite | NULL | 2024-05-20
-- Renew SSL cert | High | 2024-06-01
-- Review PR | Medium | 2024-06-04
SELECT task_name, priority, due_date
FROM tasks
ORDER BY
CASE priority
WHEN 'High' THEN 1
WHEN 'Medium' THEN 2
WHEN 'Low' THEN 3
ELSE 4
END,
due_date;
-- Output:
-- task_name | priority | due_date
-- ---------------+----------+-----------
-- Renew SSL cert | High | 2024-06-01
-- Fix login bug | High | 2024-06-10
-- Review PR | Medium | 2024-06-04
-- Update docs | Low | 2024-06-03
-- Plan offsite | NULL | 2024-05-20
ORDER BY 관련 추가 자료
이 블로그의 글:
- SQL GROUP BY 가이드: 매출 상위 카테고리처럼 그룹화한 결과 정렬하기
- SQL CASE 문 가이드: 사용자 지정 정렬을 위한 CASE 표현식
- PostgreSQL, MySQL, SQLite, SQL Server에서 행 수 제한하기: LIMIT, OFFSET, TOP
- MySQL 상위 N개 행 조회하기: MySQL에서 ORDER BY와 LIMIT 함께 쓰기
-
SQL 중복 찾기 가이드:
ROW_NUMBER()안의 ORDER BY로 어떤 행을 원본으로 볼지 정하기
공식 문서:
Beekeeper Studio는 무료 오픈 소스 데이터베이스 GUI예요
지금까지 써 본 SQL 쿼리 & 에디터 도구 중 최고예요. 데이터베이스 관리에 필요한 모든 게 다 있어요. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio는 빠르고 직관적이며 사용하기 쉬워요. 다양한 데이터베이스를 지원하고 Windows, Mac, Linux에서 모두 잘 작동해요.
Beekeeper Studio 사용자 후기
"Beekeeper Studio가 기존 SQL 작업 방식을 완전히 대체했어요. 빠르고 직관적이라 데이터베이스 작업이 다시 즐거워졌어요."
"여러 데이터베이스 GUI를 써 봤지만, Beekeeper는 기능과 단순함 사이의 균형이 완벽해요. 그냥 잘 돼요."