SQL에서 고유한 레코드를 추출하는 것은 조직들이 다차원 데이터를 저장하기 시작하면서 매우 중요한 작업이 되었습니다. 때때로 여러 열의 조합에 대해 중복되지 않는 행을 출력해야 하고, 때때로 단일 키만 필요합니다.
문제의 역사:
초기 SQL 버전에서는 중복을 필터링하기 위해 DISTINCT만 제공되었습니다. 이후 GROUP BY와 같은 구조적 방법이 생겼고, UNIQUE한 값 집합에 대한 집계를 위한 것이며, 중복 레코트 처리에 대해 더 유연한 시나리오를 위한 ROW_NUMBER()와 같은 창 함수도 도입되었습니다. 예를 들어, '마지막' 또는 '첫 번째' 레코드를 선택할 수 있습니다.
문제:
DISTINCT는 SELECT에서 필드 집합 수준에서만 작동하지만 GROUP BY는 집계를 요구합니다. 창 함수는 고급 로직을 허용하지만 행 선택 순서를 충분히 고려하지 않으면 오류를 유발할 수 있습니다. 개발자들은 종종 이러한 접근 방식을 혼동하며, 이러한 오류는 잘못된 결과로 이어질 수 있습니다.
해결책:
코드 예제:
고객별로 가장 최근의 주문 레코드를 하나 선택하기:
WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;
주요 특징:
GROUP BY 없이 집계 함수와 함께 DISTINCT를 사용할 수 있습니까?
아니요, 집계 함수는 그룹화를 요구하며, 그렇지 않으면 구문 오류가 발생합니다.
SELECT COUNT(DISTINCT CustomerID) -- 올바름 SELECT SUM(Amount), DISTINCT CustomerID -- 오류!
GROUP BY에 SELECT의 모든 비집계 필드를 지정하지 않으면 어떻게 되나요?
이것은 대부분의 DBMS에서 오류를 발생시킵니다: SELECT의 모든 필드(집계 제외)는 GROUP BY에 나열되어야 합니다.
서브쿼리 없이 창 함수를 사용하여 중복을 '제거'할 수 있습니까?
아니요: 하나의 SELECT 내에서 ROW_NUMBER()를 사용한다고 해서 자동으로 '중복'을 필터링하지 않으며, 원하는 행을 선택하기 위한 외부 쿼리가 필요합니다.
20백만 행의 테이블에 대해 모든 열에 대해 DISTINCT를 선택했습니다: 쿼리는 몇 시간 동안 실행되었고, 결과는 타임 아웃이나 데이터베이스 성능 저하였습니다.
장점:
단점:
창 함수를 사용하여: 고객에 대한 필요한 최신 레코드만 수 밀리초 내에 얻었습니다; 이전 및 반복할 필요가 없었습니다.
장점:
단점: