OVER()는 SQL한테 어떤 행 집합에 윈도우 함수를 적용할지 알려주는 명령어야. 쉽게 말해서, 데이터에 "윈도우"를 어떻게 정할지 지정하는 방법이지. 예를 들어, 방에 사람들이 가득 있는데, 바닥의 각 평방미터마다 몇 명이 서 있는지 세고 싶다고 해보자. OVER()는 우리가 방의 어느 부분에 집중할지 정해주는 거야. 다시 말해서, 함수가 어떤 행 집합에 적용될지 지정하는 거지.
OVER() 연산자는 윈도우 함수랑만 같이 써서, 한 개 또는 여러 테이블의 행에 연산을 할 수 있어. 이때 데이터 그룹화는 안 해.
문법:
윈도우_함수() OVER (
[PARTITION BY ...]
[ORDER BY ...]
[ROWS/RANGE ...]
)
여기서:
PARTITION BY— 데이터 집합을 논리적인 그룹으로 나눔ORDER BY— 각 그룹 안에서 행의 순서를 정함ROWS/RANGE— "윈도우"의 크기를 지정함 (예: 현재 행 + 다음 1개)
예시: OVER() 파라미터 없이 쓰기
OVER()를 아무 옵션 없이 쓰면, 그 앞에 있는 함수가 전체 데이터 집합에 적용된다는 뜻이야.
SELECT
employee_id,
salary,
ROW_NUMBER() OVER () AS row_num -- ROW_NUMBER()는 결과의 모든 행에 적용됨
FROM employees;
무슨 일이 일어나냐면?
ROW_NUMBER()가 각 행에 고유 번호를 붙여줘.OVER()에 아무 옵션도 없으니까,employees테이블의 모든 행을 하나의 집합으로 처리해.
결과:
| employee_id | salary | row_num |
|---|---|---|
| 1 | 50000 | 1 |
| 2 | 60000 | 2 |
| 3 | 55000 | 3 |
PARTITION BY로 그룹 나누기
좋아, 이제 회사 전체가 아니라 각 부서 안에서 직원 번호를 매기고 싶다고 해보자. 이럴 때 PARTITION BY가 등장해.
OVER() 안의 PARTITION BY는 데이터를 그룹(또는 "섹션")으로 나눠. 각 그룹마다 함수가 따로 값을 계산해. 만약 ROW_NUMBER()가 웨이터라면, 각 "테이블"(섹션)마다 번호를 새로 매기는 거지.
예시: PARTITION BY 사용
SELECT
department_id,
employee_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id) AS row_num
FROM employees;
무슨 일이 일어나냐면?
employees테이블의 데이터가department_id값으로 그룹화돼.- 각 그룹 안에서
ROW_NUMBER()로 행마다 순번을 매겨.
결과:
| department_id | employee_id | salary | row_num |
|---|---|---|---|
| 1 | 1 | 50000 | 1 |
| 1 | 3 | 55000 | 2 |
| 2 | 2 | 60000 | 1 |
ORDER BY로 순서 정하기
이제 좀 더 구조를 추가해보자. 그냥 번호만 매기는 게 아니라, 예를 들어 가장 높은 연봉부터 순번을 매기고 싶을 수도 있잖아? 이럴 때 ORDER BY를 쓰면 돼.
ORDER BY는 윈도우 함수가 행을 어떤 순서로 처리할지 정해줘.
예시: OVER() 안에 ORDER BY 쓰기
SELECT
department_id,
employee_id,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank
FROM employees;
무슨 일이 일어나냐면?
- 데이터가 (
PARTITION BY department_id)로 그룹화돼. - 각 그룹 안에서 행이 연봉 내림차순(
ORDER BY salary DESC)으로 정렬돼. - 정렬된 순서대로 각 행에 랭크가 매겨져.
결과:
| department_id | employee_id | salary | rank |
|---|---|---|---|
| 1 | 3 | 55000 | 1 |
| 1 | 1 | 50000 | 2 |
| 2 | 2 | 60000 | 1 |
윈도우 함수 여러 개 조합하기
SQL에서는 한 쿼리에서 여러 윈도우 함수를 쓸 수 있어. 각 함수마다 자기만의 규칙으로 동작하지! 마치 한 방에서 음악도 틀고, 사람 수도 세는 것처럼, 각각 따로 돌아가는 거야!
예시: 여러 윈도우 함수
SELECT
department_id,
employee_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num,
AVG(salary) OVER (PARTITION BY department_id) AS avg_salary
FROM employees;
무슨 일이 일어나냐면?
ROW_NUMBER()는 각 그룹에서 연봉 내림차순으로 행에 번호를 매겨.AVG()는 각 그룹의 평균 연봉을 계산해.
결과:
| department_id | employee_id | salary | row_num | avg_salary |
|---|---|---|---|---|
| 1 | 3 | 55000 | 1 | 52500 |
| 1 | 1 | 50000 | 2 | 52500 |
| 2 | 2 | 60000 | 1 | 60000 |
실생활 예시
OVER()랑 윈도우 함수는 진짜 여러 상황에서 써! 예를 들면:
- 판매 분석: 각 카테고리별로 상품을 판매량 순위로 매기기
- 랭킹: 각 그룹에서 학생들의 평균 점수로 순위 정하기
- 시계열: 시간별 누적 판매 합계 구하기
판매 분석 예시:
SELECT
category_id,
product_id,
product_name,
SUM(sales) OVER (PARTITION BY category_id ORDER BY sales DESC) AS cumulative_sales
FROM products;
윈도우 함수 쓸 때 자주 하는 실수
PARTITION BY안 쓰기
PARTITION BY를 안 쓰면, 윈도우 함수가 테이블 전체에 적용돼. 그룹별로 나눠서 결과를 기대했다면, 예상과 다르게 나올 수 있어.
💡 테이블을 어떻게 나눌지(예: 사용자, 주문, 카테고리 등) 명확하게 PARTITION BY로 지정해줘!
ORDER BY에서 데이터 타입 잘못 쓰기
윈도우 함수 안의 ORDER BY는 데이터 타입에 민감해. 만약 날짜 필드를 VARCHAR로 저장했다면, 정렬이 알파벳 순서로 될 수도 있고, 시간 순서가 아닐 수도 있어.
💡 정렬 전에 그런 필드는 꼭 DATE, INTEGER 등 필요한 타입으로 변환해!
ROWS BETWEEN잘못 쓰기
윈도우 함수는 기본적으로 ROWS BETWEEN으로 범위를 정해. 만약 명확하게 범위를 지정 안 하면, RANGE가 적용돼서 예상보다 더 많은 행이 결과에 포함될 수 있어.
💡 누적 합계처럼 처음부터 현재 행까지 합치고 싶으면 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW를 써!
NULL처리 실수
윈도우 함수는 NULL을 다루는 방식이 다를 수 있어. 예를 들어, RANK()나 DENSE_RANK()는 NULL도 값으로 보고, 따로 랭크를 매겨.
💡 ORDER BY에서 NULLS LAST나 NULLS FIRST를 써서 NULL이 어디에 올지 정해!
- 일반 집계 함수 대신 윈도우 집계 함수 쓰기
가끔 SUM() OVER(...) 같은 윈도우 집계 함수를 GROUP BY로 충분한 상황에서도 써서, 쿼리가 복잡해지고 느려질 수 있어.
💡 행별 상세 정보가 꼭 필요할 때만 윈도우 함수를 써!
GO TO FULL VERSION