일을 하다 보면 데이터가 중복으로 들어가 있는 테이블에서 특정 조건을 만족하는 데이터만 조회하는 경우가 정말 많다.
매번 찾아보기도 힘들고 한번 알아두면 누구보다 빠르게 쿼리를 작성할 수 있기 때문에 처음이자 마지막으로 정리를 하려고 한다.
우선 GROUP BY는 각종 집계함수, 그룹함수와 함께 쓰이며 그룹화된 정보를 제공한다. 데이터를 그룹으로 나누어, 그룹별로 집계된 정보를 출력하고 비교할 때 GROUP BY 가 사용된다.
GROUP BY로 그룹화된 결과에 대해 조건을 걸 수 있는데 이것이 HAVING 절이다. 그룹별로 적용할 수 있는 함수 및 연산자를 사용할 수 있다.
1. HAVING에서 사용할 수 있는 연산자
연산자 | 설명 | 예제 |
= | 특정 값과 같은 그룹 선택 | HAVING COUNT(*) = 10 |
!=, <> | 특정 값과 다른 그룹 선택 | HAVING COUNT(*) <> 5 |
>, <, >=, <= | 특정 값보다 크거나 작은 그룹 선택 | HAVING SUM(salary) > 50000 |
IN | 특정 값 목록에 포함된 그룹 선택 | HAVING department IN ('HR', 'IT') |
NOT IN | 특정 값 목록에 포함되지 않은 그룹 선택 | HAVING department NOT IN ('HR', 'IT') |
BETWEEN | 값의 범위를 지정 | HAVING SUM(sales) BETWEEN 10000 AND 50000 |
LIKE | 특정 패턴과 일치하는 그룹 선택 | HAVING department LIKE 'Tech%' |
IS NULL, IS NOT NULL | 그룹 내 집계 결과가 NULL인지 확인 | HAVING AVG(salary) IS NOT NULL |
2. HAVING에서 사용할 수 있는 집계 함수
HAVING 절에서는 GROUP BY로 묶인 그룹에 대한 집계 함수(Aggregate Function)를 사용할 수 있다.
집계 함수 | 설명 | 예제 |
COUNT(*) | 그룹 내 행 개수 | HAVING COUNT(*) > 5 |
COUNT(column) | 특정 컬럼 값이 NULL이 아닌 행 개수 | HAVING COUNT(department) > 10 |
SUM(column) | 그룹 내 합계 | HAVING SUM(sales) > 50000 |
AVG(column) | 그룹 내 평균 | HAVING AVG(salary) >= 40000 |
MIN(column) | 그룹 내 최소값 | HAVING MIN(salary) > 20000 |
MAX(column) | 그룹 내 최대값 | HAVING MAX(salary) < 100000 |
STDDEV(column) | 그룹 내 표준편차 | HAVING STDDEV(salary) > 10000 |
VARIANCE(column) | 그룹 내 분산 | HAVING VARIANCE(salary) > 5000 |
MEDIAN(column) | 그룹 내 중앙값 (Oracle 전용) | HAVING MEDIAN(salary) > 45000 |
3. HAVING에서 여러 조건을 조합하는 논리 연산자
여러 조건을 AND, OR, NOT 연산자로 조합할 수 있다.
연산자 | 설명 | 예제 |
AND | 여러 조건을 모두 만족해야 함 | HAVING COUNT(*) > 5 AND SUM(sales) > 10000 |
OR | 하나라도 만족하면 선택 | HAVING COUNT(*) > 5 OR SUM(sales) > 10000 |
NOT | 특정 조건을 제외 | HAVING NOT COUNT(*) > 10 |
4. HAVING 절 예제
4-1. COUNT() 사용하여 특정 개수 이상인 그룹만 조회
SELECT department, COUNT(*) AS employee_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
* 각 부서별 직원 수가 5명 이상인 부서만 조회
4-2. SUM() 사용하여 총 매출이 50,000 이상인 그룹만 조회
SELECT region, SUM(sales) AS total_sales
FROM sales_data
GROUP BY region
HAVING SUM(sales) >= 50000;
* 각 지역(region)별 총 매출이 50,000 이상인 그룹만 조회
4-3. AVG() + MAX() 사용
SELECT department, AVG(salary) AS avg_salary, MAX(salary) AS max_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 40000 AND MAX(salary) < 100000;
* 부서별 평균 급여가 40,000 이상이고, 최대 급여가 100,000 미만인 부서만 조회
4-4. COUNT(DISTINCT column) 사용하여 중복 제거 후 개수 비교
SELECT category, COUNT(DISTINCT product_id) AS unique_products
FROM products
GROUP BY category
HAVING COUNT(DISTINCT product_id) > 10;
* 카테고리별 고유한 상품 개수가 10개 이상인 경우만 조회
4-5. HAVING + ORDER BY 함께 사용
SELECT department, COUNT(*) AS employee_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5
ORDER BY employee_count DESC;
* 직원 수가 5명 이상인 부서를 조회하면서, 직원 수가 많은 순으로 정렬
COUNT() 함수
오라클에서 COUNT() 함수는 특정 컬럼 또는 표현식의 개수를 세는 집계함수이다.
HAVING COUNT(*) 에서 괄호 안 * 에 들어갈 수 있는 요소를 정리해보자.
1. COUNT(*) (전체 행 개수)
SELECT department, COUNT(*) AS total_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
* 각 부서별 총 직원 수가 5명 이상인 부서만 조회
* NULL 값을 포함한 모든 행을 개수로 셈
2. 특정 컬럼 값 개수( COUNT(column) )
SELECT department, COUNT(salary) AS non_null_salaries
FROM employees
GROUP BY department
HAVING COUNT(salary) > 5;
* 부서별 salary가 NULL이 아닌 행의 개수를 카운트
* NULL 값은 개수에서 제외된다!!!!!!
3. DISTINCT을 사용하여 중복 제거한 개수( COUNT(DISTINCT column) )
SELECT department, COUNT(DISTINCT job_title) AS unique_jobs
FROM employees
GROUP BY department
HAVING COUNT(DISTINCT job_title) > 3;
* 부서별 중복되지 않은 직무(job_title) 개수가 3개 이상인 부서만 조회
* NULL 값은 개수에서 제외된다.
4. 특정 조건을 만족하는 값 개수 ( COUNT(CASE WHEN ...) )
SELECT department,
COUNT(CASE WHEN salary > 50000 THEN 1 END) AS high_salary_count
FROM employees
GROUP BY department
HAVING COUNT(CASE WHEN salary > 50000 THEN 1 END) > 3;
* 급여(salary)가 50,000 이상인 직원 수가 3명 이상인 부서만 조회
* 조건을 만족하지 않는 행은 개수에서 제외됨
5. 다중 도건 사용 ( COUNT(CASE WHEN ...) 여러개 ) ** 이걸 쓸 일이 많다.
SELECT department,
COUNT(CASE WHEN salary > 50000 THEN 1 END) AS high_salary_count,
COUNT(CASE WHEN job_title = 'Manager' THEN 1 END) AS manager_count
FROM employees
GROUP BY department
HAVING COUNT(CASE WHEN salary > 50000 THEN 1 END) > 3
AND COUNT(CASE WHEN job_title = 'Manager' THEN 1 END) > 2;
* 급여 50,000 이상 직원 수가 3명 이상이고, 매니저가 2명 이상인 부서만 조회
6. NULL 값 포함 여부 체크 ( COUNT(NULLIF(column, 조건)) )
SELECT department, COUNT(NULLIF(salary, 0)) AS non_zero_salaries
FROM employees
GROUP BY department
HAVING COUNT(NULLIF(salary, 0)) > 5;
* 급여가 0이 아닌 직원 수가 5명 이상인 부서만 조회
* NULLIF(salary, 0)는 salary가 0이면 NULL 로 변환하여 COUNT 에서 제외시킨다.
7. 조합 사용 (COUNT + SUM/AVG 등)
SELECT department, COUNT(*) AS total_employees, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING COUNT(*) > 10 AND SUM(salary) > 500000;
* 직원 수가 10명 이상이고, 급여 총합이 500,000 이상인 부서만 조회
외울건 아니지만 이런 경우에 이런걸 쓰는구나~ 라는걸 알고 있으면 쿼리를 짤때 도움이 많이 될 것 같다.
'Back-End > DB' 카테고리의 다른 글
오라클 날짜별 조회 (0) | 2025.04.07 |
---|---|
오라클 ORA-00054 : 리소스가 사용 중이어서 NOWAIT가 지정되었거나 시간 초과가 만료된 상태로 획득합니다. (0) | 2025.04.03 |
오라클 MERGE INTO 구문과 INACTIVE (1) | 2024.10.18 |
DB Connection is not associated (1) | 2024.09.10 |
인덱스 구조 및 탐색 (0) | 2024.08.05 |