Programming

📌 MSSQL에서 그룹별 최신 데이터 가져오기

quantoasis 2025. 3. 9. 10:28
반응형

 

(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쿼리 #윈도우함수

반응형