728x90
반응형
프로젝트 중 UI팝업을 누르면 사용자가 최근 사용한 주소 10개 데이터를 그리드로 출력해야 되는 화면이 있었다.
프론트 쪽에서는 사실 그리드에 데이터만 뿌려주면 되고, 적용버튼(or 더블클릭이벤트)이 눌리면 선택된 주소가 자동으로 텍스트박스에 바인드 되는 정도의 기능만 있으면 돼서, 쿼리만 잘 짜주면 되겠다 생각했다.
내가 생각했던 쿼리는 최근 사용 주소 '10개' 니까 사용자id에 따라 RANK로 묶어서 RN <= 10 이렇게 두면 해당 사용자에 대한 최근 주소데이터 10개를 조회한다고 생각했다.
아래와 같은 예제 데이터가 있다고 가정해보자.
예제 데이터
원하는 출력 결과
1. RANK() 사용 (잘못된 방식)
SELECT *
FROM (
SELECT *,
RANK() OVER (PARTITION BY user_id ORDER BY used_at DESC) AS rn
FROM recent_addresses
WHERE user_id = 101
) ranked
WHERE rn <= 10;
이런 식으로 짜면 최근 10개의 사용주소가 나올 줄 알았는데 , 14rows의 결과가 나왔다. 알고 보니, rank는 중복이 가능했고 1, 2, 3, 4, ... 순차적으로 쌓이는 것이 아니라, 만약 기준 데이터가 동일하다면? 1, 2, 2, 3, 4, .. 이런식으로 중복되는 rank도 집계가 되는 것이었다.
그래서 rank <= 10 조건으로 두면 1, 2, 2, 3, 4, 5, 5, 5, 6, ... 이런 식으로 중복되는 모든 숫자들을 보여주기에 10개가 넘을 수도 있다.
2. ROW_NUMBER() 사용 (올바른 방식)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY used_at DESC) AS rn
FROM recent_addresses
WHERE user_id = 101
) numbered
WHERE rn <= 10;
위처럼 ROW_NUMBER()로 두면, 순번이 순차적으로 중복없이 쌓이기 때문에 10개의 결과데이터가 나온다.
- ROW_NUMBER()를 사용하여 중복되지 않는 연속적인 번호를 부여.
- WHERE rn <= 10 조건을 사용하여 정확히 10개의 최근 사용 주소를 가져옴.
특정 user_id의 최근 사용 주소 10개를 가져올 때는 RANK()가 아니라 ROW_NUMBER()를 사용해야 정확한 개수를 유지할 수 있다.
최종 결론
함수 | 중복처리방식 | 건너뛰는 순위 여부 | 사용 경우 추천 |
ROW_NUMBER() | 각 행에 고유한 번호 부여 | ❌ 없음 (연속된 번호) | 정확히 N개의 데이터를 가져와야 할 때 |
RANK() | 동일 값이면 같은 순위 부여 | ✅ 있음 (건너뜀) | 중복된 순위를 고려해야 할 때 |
728x90
반응형
'실무' 카테고리의 다른 글
[DB] ROWNUM 사용 시 주의점/활용법 | 민민의 하드디스크 - 티스토리 (0) | 2025.03.07 |
---|---|
[DB]Mybatis insert/update 시퀀스 관리 | 민민의 하드디스크 - 티스토리 (0) | 2025.03.07 |