ROW_NUMBER() 개념 및 사용법 (MSSQL)ROW_NUMBER() 함수는 각 행에 고유한 순번을 부여하는 윈도우 함수입니다.
주로 데이터 정렬, 순위 매기기, 페이징 처리 등에 사용됩니다.
SELECT
컬럼명,
ROW_NUMBER() OVER (PARTITION BY 그룹 기준 컬럼 ORDER BY 정렬 기준 컬럼) AS RowNum
FROM 테이블명;
PARTITION BY: 그룹별로 순번을 매김 (선택 사항, 없으면 전체 데이터에 적용)ORDER BY: 순번을 부여할 때 정렬 기준 지정 (필수)테이블 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 |
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 기준으로 순번을 매깁니다.
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페이지 데이터)
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 그룹에서 첫 번째 데이터만 남기고 나머지는 삭제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() 추천RANK() 또는 DENSE_RANK()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;
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페이지
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;