(ROW_NUMBER vs RANK vs PARTITION BY 비교)
MSSQL에서 그룹별 최신 데이터를 가져올 때 가장 많이 사용하는 기법이 **윈도우 함수(Window Function)**입니다.
대표적으로 ROW_NUMBER(), RANK(), DENSE_RANK()를 활용할 수 있는데요.
각 함수의 차이점을 알아보고 가장 효율적인 데이터 추출 방법을 비교해보겠습니다. 🚀
🎯 1. 윈도우 함수란?
윈도우 함수(Window Function)는 집계 함수(Aggregate Function)와 비슷하지만, 그룹화된 결과를 개별 행에도 적용할 수 있는 함수입니다.
주로 PARTITION BY와 함께 사용되며, 특정 그룹 내에서 순위를 매기거나 특정 조건을 적용할 때 유용합니다.
사용할 수 있는 주요 윈도우 함수:
- ROW_NUMBER() : 각 그룹별로 고유한 순번을 부여
- RANK() : 순위를 부여하지만 동순위가 존재하면 다음 순위는 건너뜀
- DENSE_RANK() : RANK()와 비슷하지만, 동순위가 존재해도 다음 순위가 건너뛰지 않음
🎯 2. 샘플 데이터 생성
다음과 같은 Sales 테이블이 있다고 가정해보겠습니다.
이 테이블에서 각 고객(CustomerID)별로 가장 최신 구매 내역(가장 큰 OrderDate)을 가져오는 방법을 살펴보겠습니다.
CREATE TABLE Sales (
SaleID INT PRIMARY KEY,
CustomerID INT,
OrderDate DATETIME,
Amount DECIMAL(10, 2)
);
INSERT INTO Sales (SaleID, CustomerID, OrderDate, Amount) VALUES
(1, 101, '2024-03-01', 100.00),
(2, 101, '2024-03-05', 150.00),
(3, 101, '2024-03-10', 200.00), -- 최신 데이터
(4, 102, '2024-02-15', 300.00),
(5, 102, '2024-02-20', 350.00),
(6, 102, '2024-03-01', 400.00), -- 최신 데이터
(7, 103, '2024-02-01', 500.00),
(8, 103, '2024-03-02', 550.00), -- 최신 데이터
(9, 103, '2024-03-02', 550.00); -- 동순위 데이터
🎯 3. ROW_NUMBER() 사용 (가장 추천!)
ROW_NUMBER()는 각 그룹별로 유일한 순번을 부여합니다.
이것을 활용하여 각 고객별 최신 주문만 가져올 수 있습니다.
WITH RankedSales AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS RowNum
FROM Sales
)
SELECT * FROM RankedSales WHERE RowNum = 1;
✅ 결과 (각 CustomerID의 최신 주문만 가져옴)
SaleID CustomerID OrderDate Amount RowNum
3 | 101 | 2024-03-10 | 200.00 | 1 |
6 | 102 | 2024-03-01 | 400.00 | 1 |
8 | 103 | 2024-03-02 | 550.00 | 1 |
✅ 장점
- 각 그룹별 고유한 순번을 부여하므로, 단 하나의 최신 데이터만 가져오는 경우에 최적!
- 중복 없이 정확히 하나의 행만 출력됨.
- TOP 1과 비슷한 효과를 내면서도 각 그룹별로 따로 적용할 수 있음.
🎯 4. RANK() 사용 (동일한 순위가 존재)
RANK()는 동일한 값을 가진 행에 대해 같은 순위를 부여하며, 다음 순위는 건너뜁니다.
WITH RankedSales AS (
SELECT *,
RANK() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS RankNum
FROM Sales
)
SELECT * FROM RankedSales WHERE RankNum = 1;
✅ 결과 (동순위 존재 가능)
SaleID CustomerID OrderDate Amount RankNum
3 | 101 | 2024-03-10 | 200.00 | 1 |
6 | 102 | 2024-03-01 | 400.00 | 1 |
8 | 103 | 2024-03-02 | 550.00 | 1 |
9 | 103 | 2024-03-02 | 550.00 | 1 |
✅ 장점 & 단점
- 장점: 최신 데이터가 동일한 날짜로 여러 개 존재할 경우, 모두 가져올 수 있음
- 단점: 원하지 않는 중복 행이 포함될 가능성이 있음
🎯 5. DENSE_RANK() 사용 (연속 순위 부여)
DENSE_RANK()는 RANK()와 비슷하지만, 동순위가 있어도 다음 순위를 건너뛰지 않음.
WITH RankedSales AS (
SELECT *,
DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS DenseRankNum
FROM Sales
)
SELECT * FROM RankedSales WHERE DenseRankNum = 1;
✅ 결과 (RANK()와 동일하지만, 순위가 연속됨)
SaleID CustomerID OrderDate Amount DenseRankNum
3 | 101 | 2024-03-10 | 200.00 | 1 |
6 | 102 | 2024-03-01 | 400.00 | 1 |
8 | 103 | 2024-03-02 | 550.00 | 1 |
9 | 103 | 2024-03-02 | 550.00 | 1 |
✅ 장점 & 단점
- 장점: RANK()와 마찬가지로 동순위 데이터를 포함할 수 있음
- 단점: 여전히 중복이 발생할 가능성이 있음
🎯 6. 결론: 언제 어떤 방법을 써야 할까?
방법 중복 제거 장점 단점
ROW_NUMBER() | ✅ | 가장 최신 데이터 1개만 가져옴 (가장 추천) | 동순위 데이터가 있을 경우 무조건 1개만 선택됨 |
RANK() | ❌ | 최신 데이터가 여러 개 있을 경우 모두 포함 | 중복 발생 가능 |
DENSE_RANK() | ❌ | 최신 데이터가 여러 개 있어도 연속된 순위 유지 | 중복 발생 가능 |
📌 결론:
- 최신 데이터 1개만 가져오려면 → ROW_NUMBER() ✅ 추천!
- 최신 데이터가 여러 개 있다면 → RANK() or DENSE_RANK()
이제 ROW_NUMBER()를 활용해 효율적으로 그룹별 최신 데이터를 추출해보세요! 🚀
🏷 태그
#MSSQL #ROW_NUMBER #RANK #PARTITION_BY #SQL쿼리 #윈도우함수
'Programming' 카테고리의 다른 글
🚀 MSSQL에서 동적 SQL(Dynamic SQL) 활용하기 (0) | 2025.03.11 |
---|---|
🚀MSSQL에서 CTE (Common Table Expression) 활용법 (0) | 2025.03.10 |
🔗 MSSQL에서 JOIN 다루기 – 기본부터 고급 활용까지! 🚀 (0) | 2025.03.08 |
🛠 MSSQL에서 STRING 조작 (문자열 합치기, 자르기, 치환하기) (0) | 2025.03.07 |
💡 MSSQL에서 날짜(VARCHAR ↔ DATE) 변환 방법 총정리 (0) | 2025.03.06 |