✅ GROUP BY / HAVING 관련 SELECT 컬럼 정리 + 데이터 출력 활용법
📘 1. GROUP BY의 기본 개념 복습
SELECT 컬럼, 집계함수
FROM 테이블
GROUP BY 컬럼;
- GROUP BY는 특정 컬럼 값을 기준으로 행들을 그룹화
- 그룹별로 집계함수(Aggregate Function)를 함께 사용
보통 GROUP BY
에 사용된 컬럼을 SELECT
에 포함시킵니다.
집계 함수만 사용하면 어떤 기준으로 집계된 것인지 알기 어렵기 때문에, GROUP BY
컬럼을 함께 조회하여 무엇에 대한 집계인지 더 명확하게 보여줄 수 있습니다.
✅ 2. SELECT 절에 올 수 있는 컬럼 종류 (GROUP BY 사용 시)
SELECT에 올 수 있는 컬럼 종류 | 조건 | 예시 |
---|---|---|
① GROUP BY에 명시된 컬럼 | 가능 | SELECT department |
② 집계 함수로 계산된 컬럼 | 가능 | SELECT COUNT(*), SUM(salary) |
③ 집계된 결과 기반의 표현식 | 가능 | SELECT ROUND(AVG(score), 1) |
④ 상수 값 | 가능 | SELECT '기본값' AS type |
⑤ GROUP BY에 없고 집계도 안 된 컬럼 | ❌ 오류 발생 (ONLY_FULL_GROUP_BY 설정 시) |
❗ 예외 규칙
-- 잘못된 예 (MySQL 5.7 이상에서는 오류)
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;
name은 GROUP BY에 포함되어 있지도 않고 집계되지도 않아서 모호한 값 발생
✅ 3. 자주 사용하는 집계 함수
함수 | 설명 |
---|---|
COUNT(*) , COUNT(col) |
행 수, NULL 제외한 수 |
SUM(col) |
총합 |
AVG(col) |
평균 |
MIN(col) , MAX(col) |
최소/최대 값 |
SELECT department, COUNT(*) AS 인원수, AVG(salary) AS 평균급여
FROM employees
GROUP BY department;
✅ 4. SELECT 예시: 집계 + 표현식 + 정렬 + 필터링
SELECT
category,
COUNT(*) AS 제품수,
ROUND(AVG(price), 2) AS 평균가,
MAX(price) AS 최고가,
MIN(price) AS 최저가
FROM products
WHERE status = 'active'
GROUP BY category
HAVING COUNT(*) >= 5
ORDER BY 평균가 DESC;
📌 기능 설명:
WHERE
: 그룹화 전 필터링GROUP BY
: 카테고리별 묶기HAVING
: 그룹화 결과 필터SELECT
: 그룹 기준 + 집계 결과 + 표현식 출력ORDER BY
: 정렬 기준은 집계 컬럼 별칭 가능
✅ 5. SELECT에서 표현식 사용 가능 예시
SELECT
region,
COUNT(*) AS 인구수,
SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) AS 남성수,
SUM(CASE WHEN gender = 'F' THEN 1 ELSE 0 END) AS 여성수,
ROUND(SUM(income) / COUNT(*), 2) AS 1인당수입
FROM citizens
GROUP BY region
HAVING SUM(income) > 1000000;
📌 핵심 포인트:
CASE WHEN
을 써서 조건별 집계 가능ROUND
,/
,+
등 수학식도 SELECT 내 자유롭게 사용 가능
✅ 6. HAVING 절의 필터링 대상
- GROUP BY 이후 집계된 값을 필터링
- SELECT 절에 별칭으로 지정한 컬럼도 HAVING에서 사용 가능
SELECT department, COUNT(*) AS 인원수
FROM employees
GROUP BY department
HAVING 인원수 >= 5;
✔️ HAVING COUNT(*) >= 5
도 가능
✔️ HAVING 인원수 >= 5
도 가능
✅ 7. 실무 예제 정리
📍 예제 1: 고객 등급별 평균 주문 금액
SELECT grade,
COUNT(*) AS 주문수,
ROUND(AVG(total_amount), 0) AS 평균주문금액
FROM orders
GROUP BY grade
HAVING 평균주문금액 > 100000;
📍 예제 2: 월별 판매 통계
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS 월,
COUNT(*) AS 주문수,
SUM(amount) AS 총판매액
FROM orders
GROUP BY 월
ORDER BY 월;
📍 예제 3: 다중 컬럼 그룹화
SELECT
department, gender,
COUNT(*) AS 인원수
FROM employees
GROUP BY department, gender;
✅ 8. 성능 및 실무 팁
팁 | 설명 |
---|---|
GROUP BY 대상은 인덱스가 있을수록 빠름 |
특히 많은 그룹일 경우 효과 큼 |
HAVING 은 WHERE로 대체할 수 있으면 WHERE로 |
성능 향상 |
SELECT 에서 불필요한 컬럼 제외 |
ONLY_FULL_GROUP_BY 오류 방지 |
GROUP + 집계 후 필터링은 무조건 HAVING |
WHERE 은 개별 행 필터링용 |
✅ 9. 결론 요약
SELECT 절에서 가능한 항목 (GROUP BY 사용 시) | 비고 |
---|---|
GROUP BY에 있는 컬럼 | OK |
집계 함수 결과 | OK |
집계 결과 + 표현식 | OK |
고정값 | OK |
집계 없는 컬럼 | ❌ 오류 발생 가능 |
GROUP BY
를 사용한 후 모든 컬럼을 SELECT하고 싶을 때, 바로 FROM절에 서브쿼리를 써서 해결하는 게 가장 일반적이다.
이걸 "인라인 뷰 (inline view)" 또는 "서브쿼리 테이블화" 전략이라고 함.
✅ 왜 GROUP BY 후 전체 컬럼을 SELECT할 수 없는가?
MySQL은 GROUP BY
사용 시,
SELECT 절에 나오는 모든 컬럼은 아래 중 하나여야 해:
GROUP BY
에 명시된 컬럼- 집계함수로 묶인 컬럼
- 위 둘을 기반으로 만든 표현식
❌ 예시: 오류 발생
SELECT *
FROM employees
GROUP BY department;
- 은
name
,salary
,hire_date
등도 포함되는데, - 이 컬럼들은
GROUP BY
나 집계 대상이 아님 - MySQL 5.7 이상에서는
ONLY_FULL_GROUP_BY
옵션 때문에 오류 발생
✅ 해결 방법: FROM절 서브쿼리 활용
SELECT *
FROM (
SELECT department,
MIN(name) AS name, -- 집계 방식 선택
MAX(salary) AS top_salary,
COUNT(*) AS 인원수
FROM employees
GROUP BY department
) AS grouped_data;
✔️ 이 방법은 GROUP BY 결과를 하나의 테이블처럼 만들어
그 안에서 SELECT * 가능하게 만든다.
📌 실전 팁: 서브쿼리 + 조인 조합도 자주 씀
예를 들어, 부서별 최고 연봉자
의 이름, 연봉, 입사일을 전부 보고 싶을 때:
-- 1단계: 부서별 최고 연봉을 먼저 서브쿼리로 추출
SELECT e.*
FROM employees e
JOIN (
SELECT department, MAX(salary) AS top_salary
FROM employees
GROUP BY department
) AS t
ON e.department = t.department AND e.salary = t.top_salary;
✔️ 이건 집계 결과와 원본 데이터를 JOIN해서 전체 컬럼 조회하는 방식.
✔️ 실무에서 아주 많이 씀 (요약 + 상세 데이터 같이 보여줄 때)
📌 요약 정리
하고 싶은 일 | 방법 |
---|---|
GROUP BY 후 전체 컬럼 SELECT | ❌ 직접 불가능 |
해결 ① | FROM절에 서브쿼리로 집계 결과 만들고 SELECT * 사용 |
해결 ② | 집계 결과를 JOIN으로 원본 테이블과 결합 |
'CS > Database' 카테고리의 다른 글
[MySQL] MySQL의 JOIN 완전 정복 + FULL OUTER JOIN 대체 방법 (0) | 2025.04.13 |
---|---|
[MySQL] SubQuery 사용 (0) | 2025.04.13 |
[MySQL] MySQL의 JOIN, 기본키(PK) (0) | 2025.04.08 |
[MySQL] MySQL의 `SELECT` 문에 나올 수 있는 요소들 (0) | 2025.04.04 |
[Database] FROM DUAL 구문 (0) | 2025.04.03 |
댓글