SQL 기초문법 정리 - ORDER BY & GROUP BY
SQL 기초문법 정리 - ORDER BY & GROUP BY
ORDER BY - 데이터 정렬
ORDER BY절은 조회된 데이터를 특정 기준으로 정렬할 때 사용한다. SELECT문의 가장 마지막에 위치한다.
기본 정렬
1
2
3
4
5
6
7
8
9
10
-- 오름차순 정렬 (기본값)
SELECT * FROM users ORDER BY age;
SELECT * FROM users ORDER BY age ASC;
-- 내림차순 정렬
SELECT * FROM users ORDER BY age DESC;
-- 문자열 정렬
SELECT * FROM users ORDER BY name;
SELECT * FROM users ORDER BY city DESC;
다중 컬럼 정렬
1
2
3
4
5
6
7
8
-- 첫 번째 기준으로 정렬 후, 같은 값일 때 두 번째 기준 적용
SELECT * FROM users ORDER BY city, age;
SELECT * FROM users ORDER BY city ASC, age DESC;
-- 도시별로 그룹화하고, 각 그룹 내에서 나이 내림차순
SELECT name, city, age
FROM users
ORDER BY city, age DESC;
계산된 값으로 정렬
1
2
3
4
5
6
7
8
9
-- 계산된 컬럼으로 정렬
SELECT name, age, age * 12 AS age_in_months
FROM users
ORDER BY age_in_months DESC;
-- 함수 결과로 정렬
SELECT name, email
FROM users
ORDER BY LENGTH(name) DESC;
집계 함수
집계 함수는 여러 행의 데이터를 하나의 결과값으로 계산하는 함수다.
기본 집계 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- COUNT: 행의 개수
SELECT COUNT(*) AS total_users FROM users;
SELECT COUNT(phone) AS users_with_phone FROM users; -- NULL 제외
-- SUM: 합계
SELECT SUM(price * quantity) AS total_revenue FROM orders;
-- AVG: 평균
SELECT AVG(age) AS average_age FROM users;
SELECT ROUND(AVG(price), 2) AS average_price FROM orders;
-- MAX/MIN: 최댓값/최솟값
SELECT MAX(age) AS oldest, MIN(age) AS youngest FROM users;
SELECT MAX(order_date) AS latest_order FROM orders;
조건부 집계
1
2
3
4
5
6
7
8
9
10
11
-- WHERE절과 함께 사용
SELECT COUNT(*) AS seoul_users
FROM users
WHERE city = '서울';
-- CASE WHEN을 활용한 조건부 카운트
SELECT
COUNT(*) AS total_users,
COUNT(CASE WHEN age >= 30 THEN 1 END) AS users_over_30,
COUNT(CASE WHEN city = '서울' THEN 1 END) AS seoul_users
FROM users;
GROUP BY - 데이터 그룹화
GROUP BY절은 특정 컬럼의 값이 같은 행들을 하나의 그룹으로 묶어 집계 함수를 적용할 때 사용한다.
기본 그룹화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 도시별 사용자 수
SELECT city, COUNT(*) AS user_count
FROM users
GROUP BY city;
-- 도시별 평균 나이
SELECT city, ROUND(AVG(age), 1) AS average_age
FROM users
GROUP BY city;
-- 사용자별 주문 통계
SELECT user_id,
COUNT(*) AS order_count,
SUM(price * quantity) AS total_amount,
AVG(price) AS average_price
FROM orders
GROUP BY user_id;
다중 컬럼 그룹화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 도시와 연령대별 그룹화
SELECT city,
CASE
WHEN age < 30 THEN '20대'
WHEN age < 40 THEN '30대'
ELSE '40대 이상'
END AS age_group,
COUNT(*) AS user_count
FROM users
GROUP BY city,
CASE
WHEN age < 30 THEN '20대'
WHEN age < 40 THEN '30대'
ELSE '40대 이상'
END;
날짜별 그룹화
1
2
3
4
5
6
7
-- 일별 주문 통계
SELECT order_date,
COUNT(*) AS order_count,
SUM(price * quantity) AS daily_revenue
FROM orders
GROUP BY order_date
ORDER BY order_date;
HAVING - 그룹 조건
HAVING절은 GROUP BY로 생성된 그룹에 조건을 적용할 때 사용한다.
WHERE절은 그룹화 이전에, HAVING절은 그룹화 이후에 조건을 적용한다.
기본 HAVING 사용
1
2
3
4
5
6
7
8
9
10
11
-- 사용자가 2명 이상인 도시만 조회
SELECT city, COUNT(*) AS user_count
FROM users
GROUP BY city
HAVING COUNT(*) >= 2;
-- 평균 나이가 28세 이상인 도시
SELECT city, ROUND(AVG(age), 1) AS average_age
FROM users
GROUP BY city
HAVING AVG(age) >= 28;
WHERE와 HAVING 함께 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 30세 미만 사용자 중에서 도시별로 2명 이상인 경우
SELECT city, COUNT(*) AS young_user_count
FROM users
WHERE age < 30
GROUP BY city
HAVING COUNT(*) >= 2;
-- 최근 1개월 주문 중 총 주문금액이 50만원 이상인 사용자
SELECT user_id,
COUNT(*) AS order_count,
SUM(price * quantity) AS total_amount
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY user_id
HAVING SUM(price * quantity) >= 500000;
성능 고려사항
인덱스 활용
1
2
3
4
5
6
-- ORDER BY 성능 향상을 위한 인덱스
CREATE INDEX idx_users_age ON users(age);
CREATE INDEX idx_orders_date ON orders(order_date);
-- GROUP BY 성능 향상을 위한 복합 인덱스
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);
쿼리 최적화
- GROUP BY절의 컬럼 순서는 인덱스 순서와 일치시키는 것이 유리
- HAVING절보다는 WHERE절을 먼저 사용하여 데이터 양 축소
- 집계 함수 내에서 복잡한 계산은 피하고, 미리 계산된 컬럼 활용
This post is licensed under CC BY 4.0 by the author.