SQL 왕초보 가이드

[SQL 03-2] SQL 윈도우 함수 완벽 정리! 🚀 초보도 쉽게 배우는 순위 & 누적 합계 계산법!

devnewsletter 2025. 2. 10. 22:32
반응형

SQL 윈도우 함수, 개념부터 실전까지 한눈에! 🚀 PARTITION BY, ORDER BY, RANK()를 활용해 부서별 급여 순위 분석 & 데이터 집계까지 완벽 마스터하세요!


SQL 왕초보 가이드 - 3단계: 윈도우 함수 활용 🎯

"부서별 최고 급여를 받는 직원을 찾고 싶은데, 어떻게 해야 하죠?" 🤔
이런 고민을 해결할 수 있도록, 오늘은 SQL 윈도우 함수 기법을 배워볼 거예요! 🚀


1️⃣ 윈도우 함수(Window Function)란?

👉 특정 그룹 안에서 순위를 매기거나, 누적 합계를 실시간으로 계산하는 SQL 함수!

  • 서브쿼리"전체 데이터를 다 조회한 후" 원하는 값을 찾는 방식이라면,
  • 윈도우 함수"각 행을 처리하면서" 특정 값을 실시간으로 계산하는 방식이에요! 📚✨

2️⃣ 윈도우 함수의 핵심 문법 3가지!

🔹 PARTITION BY → 그룹 나누기 (GROUP BY와 비슷한 역할!)

  • 데이터를 어떤 기준으로 묶을지 정하는 거예요. (예: 부서별, 카테고리별 등)
  • 📌 비유: "이 도서관 책들을 장르별로 나누고 싶어!"

🔹 ORDER BY → 그룹 내 정렬

  • 그룹 안에서 어떤 순서로 정렬할지 결정! (예: 높은 급여순, 최근 날짜순 등)
  • 📌 비유: "장르별로 나눈 후, 책을 페이지 수 순으로 정렬해!"

🔹 RANK() → 순위 매기기

  • 정렬된 데이터에 순위를 부여하는 함수!
  • 📌 비유: "이제 책마다 몇 번째로 긴 책인지 번호를 붙이자!"

💡 간단한 윈도우 함수 예제

초보자도 쉽게 이해할 수 있도록 간단한 예제를 살펴볼까요? 🎯

 

📌 예제: 각 직원의 급여가 회사 전체에서 몇 번째로 높은지 확인하기

SELECT employee_name, salary,
       RANK() OVER (ORDER BY salary DESC) AS salary_rank
FROM employees;

 

설명:

  • ORDER BY salary DESC → 급여가 높은 순서대로 정렬
  • RANK() OVER (...) → 각 직원의 급여 순위를 계산

📌 결과 예시:

employee_name salary salary_rank
Alice 8000 1
Bob 7500 2
Charlie 7500 2
David 7000 4

 

💡 동일한 급여를 가진 직원이 있을 경우, 같은 순위를 부여하며 다음 순위가 건너뛰는 방식(RANK())을 사용합니다!
💡 순위 건너뛰기 없이 연속적으로 부여하고 싶다면 DENSE_RANK()를 사용하면 됩니다!

💡 PARTITION BY를 활용한 예제

📌 예제: 각 부서별 직원의 급여 순위를 매기기

SELECT employee_name, department_id, salary,
       RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS department_salary_rank
FROM employees;

 

설명:

  • PARTITION BY department_id → 각 부서별로 데이터를 나눔
  • ORDER BY salary DESC → 부서 내에서 급여가 높은 순서대로 정렬
  • RANK() OVER (...) → 부서별 급여 순위를 매김

📌 결과 예시:

employee_name department_id salary department_salary_rank
Alice 1 8000 1
Bob 1 7500 2
Charlie 2 9000 1
David 2 8500 2

 

💡 이렇게 하면 각 부서별로 직원들의 급여 순위를 쉽게 확인할 수 있습니다! 🚀

🎯 PARTITION BYGROUP BY의 차이점은?

둘 다 데이터를 그룹화하는 기능이 있지만, 사용 방식과 결과가 완전히 다릅니다! 😲

  GROUP BY PARTITION BY
기능 데이터를 집계(aggregation)해서 줄여줌. 데이터를 그룹화하지만 행을 유지함.
결과 한 그룹당 한 줄만 남음. 각 그룹 내에서 모든 행을 유지하면서 계산을 추가함.
대표 예제 SUM(), AVG(), COUNT() 같은 집계 함수와 함께 사용. RANK(), AVG() OVER() 같은 윈도우 함수와 함께 사용.
출력 데이터 개별 행이 사라지고 집계된 결과만 남음. 기존 행이 유지되면서 추가 연산 결과가 붙음.

🏆 직접 비교하면서 이해해보기!

GROUP BY만 사용한 경우 (개별 직원 데이터가 사라짐!)
SELECT department_name, AVG(salary) AS avg_salary  
FROM employees  
GROUP BY department_name;
department_name avg_salary
IT 6500
HR 5250

 

✔ 부서별 평균 급여(avg_salary)는 나오지만, 개별 직원 데이터는 없어졌어요! 😱

PARTITION BY를 사용한 경우 (개별 직원 정보 유지!)
SELECT department_name, employee_name, salary,  
       AVG(salary) OVER (PARTITION BY department_name) AS avg_salary  
FROM employees;
department_name employee_name salary avg_salary
IT 김철수 7000 6500
IT 박영희 6000 6500
HR 이민호 5500 5250
HR 최지우 5000 5250

 

GROUP BY 없이도 개별 직원 데이터가 유지되면서 부서별 평균 급여(avg_salary)가 표시됩니다! 🎉

🚀 PARTITION BY + GROUP BY = 강력한 조합!

GROUP BY는 데이터를 집계해서 요약하는 역할을 해요. (즉, 개별 데이터가 사라짐!)
PARTITION BY는 그룹을 나누면서도 개별 데이터를 유지하는 역할을 합니다!

 

💡 그럼, 이 둘을 함께 사용하면?

  • GROUP BY로 데이터를 그룹화하면서
  • PARTITION BY를 활용해 그룹 내 개별 데이터를 유지하면서 추가 분석이 가능해요! 🎯
🏢 예제: employees 테이블에서 부서별 급여 분석하기

다음 SQL 쿼리는 부서별 직원 수, 평균 급여, 최고·최저 급여를 계산하면서, 부서별 평균 급여 순위를 매깁니다! 🔥

SELECT department_name, 
       COUNT(employee_id) AS employee_count,
       AVG(salary) AS avg_salary,
       MAX(salary) AS max_salary,
       MIN(salary) AS min_salary,
       RANK() OVER (PARTITION BY department_name ORDER BY AVG(salary) DESC) AS avg_salary_rank
FROM employees
GROUP BY department_name;
📌 쿼리 설명

1️⃣ GROUP BY department_name → 부서별로 데이터를 그룹화하여 직원 수, 평균 급여, 최고·최저 급여 계산

  • COUNT(employee_id): 부서별 직원 수
  • AVG(salary), MAX(salary), MIN(salary): 급여 통계 정보

2️⃣ RANK() OVER (PARTITION BY department_name ORDER BY AVG(salary) DESC)

  • PARTITION BY department_name: 부서별로 나누고
  • ORDER BY AVG(salary) DESC: 평균 급여 기준으로 순위를 매김
📊 실행 결과 예시
department_name employee_count avg_salary max_salary min_salary avg_salary_rank
IT 2 85,000.00 90,000.00 80,000.00 1
HR 2 52,500.00 55,000.00 50,000.00 2
Sales 2 65,000.00 70,000.00 60,000.00 3

 

💡 즉, GROUP BY로 요약된 데이터에서 PARTITION BY를 활용하면 추가 분석이 가능해져요! 🎯
📢 SQL 데이터 분석할 때, 두 개를 함께 사용하면 더 강력한 인사이트를 얻을 수 있습니다! 🚀


3️⃣ 급여가 높은 상위 3명 직원 조회 (LIMIT 활용)

목표:

  • 회사에서 가장 높은 급여를 받는 직원 상위 3명 조회

📌 예제 테이블 스키마

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    salary INT
);

 

📌 기대 결과

employee_name salary
Charlie 8000
Alice 7000
David 7500

 

📌 SQL 정답

SELECT employee_name, salary
FROM employees
ORDER BY salary DESC
LIMIT 3;

 

설명:

  • ORDER BY salary DESC → 급여를 내림차순 정렬
  • LIMIT 3급여가 가장 높은 상위 3명만 출력!

📌 같은 급여를 가진 직원도 포함하려면?

SELECT employee_name, salary,
       DENSE_RANK() OVER(ORDER BY salary DESC) AS salary_rank
FROM employees
WHERE salary_rank <= 3;

 

DENSE_RANK()를 사용하면 동일한 급여를 가진 직원도 포함됩니다! 🏆


4️⃣ 부서별 최고 급여 직원 조회 (윈도우 함수 활용)

목표:

  • 부서별 최고 급여를 받는 직원을 윈도우 함수로 더 빠르게 조회
  • WITH 키워드를 활용해봐요!

📌 예제 테이블 스키마

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    department_id INT,
    salary INT
);

CREATE TABLE departments (
    department_id INT PRIMARY KEY,
    department_name VARCHAR(50)
);

 

📌 기대 결과 (동일)

department_name employee_name max_salary
HR Alice 7000
IT Charlie 8000

 

📌 SQL 정답

WITH ranked_salaries AS (
    SELECT d.department_name, e.employee_name, e.salary,
           RANK() OVER (PARTITION BY d.department_id ORDER BY e.salary DESC) AS rnk
    FROM employees e
    JOIN departments d ON e.department_id = d.department_id
)
SELECT department_name, employee_name, salary AS max_salary
FROM ranked_salaries
WHERE rnk = 1;

 

설명:

  • RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) → 각 부서별 급여 순위를 매김
  • WHERE rnk = 1부서별 최고 급여를 받은 직원만 필터링! 🚀
  • WITH 키워드를 통해 employees와 departments 테이블을 조회한 후에, 완성된 임시 테이블을 기반으로 필터링 처리를 하기 때문에, 테이블 중복 스캔이 일어나지 않아 효율적임

🎯 윈도우 함수 활용 마무리!

오늘 배운 개념들 정리해볼까요? 🚀

 

윈도우 함수 (Window Function)

  • PARTITION BY, ORDER BY, RANK() 등을 활용해 그룹별 순위를 계산하는 강력한 기능
  • 서브쿼리보다 성능이 좋고, 더 쉽게 데이터를 다룰 수 있음

🔥 SQL 실력 레벨업! 자주 묻는 질문 (FAQ)

❓ Q. PARTITION BY와 GROUP BY는 어떻게 다를까요?
💡 GROUP BY는 데이터를 묶어서 집계 결과만 남기는 반면, PARTITION BY는 원본 데이터를 유지하면서 그룹별 분석이 가능합니다!

-- PARTITION BY: 원본 데이터를 유지하며 그룹별 평균 구하기
SELECT 사원명, 부서, 급여,  
       AVG(급여) OVER(PARTITION BY 부서) AS 부서별_평균급여  
FROM 직원;
-- GROUP BY: 데이터를 묶어서 요약된 값만 출력
SELECT 부서, AVG(급여) AS 부서별_평균급여  
FROM 직원  
GROUP BY 부서;

 

📌 차이점 요약!

  GROUP BY PARTITION BY
목적 데이터를 묶어 하나의 값으로 요약 데이터를 유지하면서 그룹별 연산
결과 행 개수 기존보다 줄어듦 기존과 동일
사용 예시 평균 급여를 출력 (부서별 1개 행) 평균 급여를 출력 (각 사원별 행 유지)

📌 다음 가이드에서는 SQL 성능 최적화와 인덱스를 활용하는 방법을 배울 예정이에요!
데이터가 많아도 빠르게 조회하는 법, 궁금하지 않나요? 😆🚀

반응형