sql - ROW_NUMBER()

강찬우·2025년 1월 6일

sql

목록 보기
3/3

ROW_NUMBER() 개념 및 사용법 (MSSQL)

ROW_NUMBER() 함수는 각 행에 고유한 순번을 부여하는 윈도우 함수입니다.
주로 데이터 정렬, 순위 매기기, 페이징 처리 등에 사용됩니다.


📌 기본 문법

SELECT 
    컬럼명, 
    ROW_NUMBER() OVER (PARTITION BY 그룹 기준 컬럼 ORDER BY 정렬 기준 컬럼) AS RowNum
FROM 테이블명;
  • PARTITION BY: 그룹별로 순번을 매김 (선택 사항, 없으면 전체 데이터에 적용)
  • ORDER BY: 순번을 부여할 때 정렬 기준 지정 (필수)

🔹 1. 기본 사용법

테이블 Employees에서 직원들에게 ROW_NUMBER()를 부여하는 예제입니다.

SELECT 
    EmployeeID, 
    Name, 
    Department, 
    ROW_NUMBER() OVER (ORDER BY EmployeeID) AS RowNum
FROM Employees;

결과 예시
| EmployeeID | Name | Department | RowNum |
|------------|-------|------------|--------|
| 101 | Alice | HR | 1 |
| 102 | Bob | IT | 2 |
| 103 | Carol | IT | 3 |
| 104 | Dave | HR | 4 |


🔹 2. PARTITION BY로 그룹별 순번 매기기

부서(Department)별로 직원들의 순번을 매기고 싶다면 PARTITION BY를 사용합니다.

SELECT 
    EmployeeID, 
    Name, 
    Department, 
    ROW_NUMBER() OVER (PARTITION BY Department ORDER BY EmployeeID) AS RowNum
FROM Employees;

결과 예시
| EmployeeID | Name | Department | RowNum |
|------------|-------|------------|--------|
| 101 | Alice | HR | 1 |
| 104 | Dave | HR | 2 |
| 102 | Bob | IT | 1 |
| 103 | Carol | IT | 2 |

💡 부서별(Department)로 나누고, 각 부서에서 EmployeeID 기준으로 순번을 매깁니다.


🔹 3. ROW_NUMBER()를 활용한 페이징 처리

예를 들어, 한 페이지에 10개씩 데이터를 보여주려면 ROW_NUMBER()를 사용한 페이징 쿼리를 작성할 수 있습니다.

WITH EmployeeRank AS (
    SELECT 
        EmployeeID, 
        Name, 
        ROW_NUMBER() OVER (ORDER BY EmployeeID) AS RowNum
    FROM Employees
)
SELECT * FROM EmployeeRank
WHERE RowNum BETWEEN 11 AND 20; -- 2페이지 (10개씩)

페이징 쿼리 해석
1. ROW_NUMBER()로 각 행에 순번을 부여 (EmployeeID 기준 정렬)
2. WHERE 절로 원하는 범위만 필터링 (BETWEEN 11 AND 20 → 2페이지 데이터)


🔹 4. ROW_NUMBER()로 중복 데이터 제거

중복 데이터를 제거할 때도 ROW_NUMBER()를 사용할 수 있습니다.

예를 들어, 같은 Name이 여러 번 등장하는 경우, 가장 최신 데이터(CreatedAt)만 남기고 중복 제거하려면:

WITH EmployeeRank AS (
    SELECT 
        EmployeeID, 
        Name, 
        CreatedAt,
        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY CreatedAt DESC) AS RowNum
    FROM Employees
)
DELETE FROM EmployeeRank WHERE RowNum > 1;

설명

  • PARTITION BY Name → 같은 이름(Name)끼리 그룹화
  • ORDER BY CreatedAt DESC → 최신 데이터 우선 정렬
  • RowNum > 1인 데이터 삭제 → 각 Name 그룹에서 첫 번째 데이터만 남기고 나머지는 삭제

🔹 5. RANK() vs DENSE_RANK() vs ROW_NUMBER() 차이점

함수중복값 발생 시순번 부여 방식
ROW_NUMBER()중복값이 있어도 순번 연속 증가1, 2, 3, 4, 5, ...
RANK()중복값이 있으면 건너뜀1, 2, 2, 4, 5, ...
DENSE_RANK()중복값이 있어도 건너뛰지 않음1, 2, 2, 3, 4, ...

✅ 예제 비교

SELECT 
    Name, 
    Score,
    ROW_NUMBER() OVER (ORDER BY Score DESC) AS RowNumber,
    RANK() OVER (ORDER BY Score DESC) AS RankNum,
    DENSE_RANK() OVER (ORDER BY Score DESC) AS DenseRankNum
FROM Students;

결과 예시
| Name | Score | RowNumber | RankNum | DenseRankNum |
|-------|-------|----------|---------|-------------|
| Alice | 98 | 1 | 1 | 1 |
| Bob | 95 | 2 | 2 | 2 |
| Carol | 95 | 3 | 2 | 2 |
| Dave | 90 | 4 | 4 | 3 |

  • ROW_NUMBER(): 순번이 연속 증가
  • RANK(): 중복값(95)이 있으면 같은 순위를 부여하고 다음 순위 건너뜀
  • DENSE_RANK(): 중복값이 있어도 순위를 건너뛰지 않음

정리

기능ROW_NUMBER()RANK()DENSE_RANK()
중복 데이터 처리중복 있어도 순번 연속 증가중복 시 건너뜀중복 시 건너뛰지 않음
페이징 처리✅ (추천)
순위 매기기
중복값 제거✅ (추천)
  • 페이징 처리, 중복 데이터 제거ROW_NUMBER() 추천
  • 순위 매기기 (1등, 2등, 3등 구별)RANK() 또는 DENSE_RANK()

🚀 실무 활용 예시

📍 1️⃣ 시간별 GROUP BY (없는 시간 포함)

WITH HourList AS (
    SELECT TOP (24) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS HourPart
    FROM master.dbo.spt_values
)
SELECT 
    H.HourPart,
    COALESCE(COUNT(O.OrderID), 0) AS OrderCount
FROM HourList H
LEFT JOIN Orders O
    ON H.HourPart = DATEPART(HOUR, O.OrderTime)
    AND CONVERT(DATE, O.OrderTime) = '2024-01-06'
GROUP BY H.HourPart
ORDER BY H.HourPart;

📍 2️⃣ 페이징 처리 (10개씩)

WITH EmployeeRank AS (
    SELECT 
        EmployeeID, 
        Name, 
        ROW_NUMBER() OVER (ORDER BY EmployeeID) AS RowNum
    FROM Employees
)
SELECT * FROM EmployeeRank
WHERE RowNum BETWEEN 11 AND 20; -- 2페이지

📍 3️⃣ 중복 데이터 제거 (최신 데이터만 유지)

WITH EmployeeRank AS (
    SELECT 
        EmployeeID, 
        Name, 
        CreatedAt,
        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY CreatedAt DESC) AS RowNum
    FROM Employees
)
DELETE FROM EmployeeRank WHERE RowNum > 1;

0개의 댓글