2003/02/11

테이블에서 중복 행을 제거하는 방법

Microsoft SQL Server 테이블에는 중복 행이나 고유하지 않은 기본 키가 없어야 합니다. 본 문서에서는 기본 키를 간략히 "키" 또는 "PK"로 지칭하기도 합니다. 그렇다고 해서 "키" 또는 "PK"가 반드시 "기본 키"를 나타내는 것은 아닙니다.

중복 PK는 엔티티 무결성을 위반하는 것이며 관계형 시스템에서는 허용되지 않습니다. SQL Server에는 엔티티 무결성을 유지하기 위한 인덱스, UNIQUE 제약 조건, PRIMARY KEY 제약 조건, 트리거 등의 다양한 메커니즘이 포함되어 있습니다.

그럼에도 불구하고 중복된 기본 키가 발생하는 예외적 경우가 있습니다. 이런 경우에는 중복된 기본 키를 제거해야 합니다. 중복 PK가 SQL Server 외부의 비관계형 데이터에 존재하고 PK 고유성이 항상 유지되도록 설정되지 않은 상태에서 데이터를 들여올 경우가 여기에 해당합니다. 각 테이블에서의 엔티티 무결성이 항상 유지되도록 설정하지 않는 등의 데이터베이스 디자인 오류로 인해서도 중복된 기본 키가 발생합니다.

대개 고유 인덱스를 만들려고 할 때 중복 PK가 발견되는데, 이런 경우에는 다음 메시지와 함께 작업이 중단됩니다. 이 메시지는 다음과 같습니다.

Msg 1505, Level 16, State 1 Create unique index aborted on duplicate key.

다음은 중복된 기본 키를 확인하고 제거하는 절차입니다.
create table t1(col1 int, col2 int, col3 char(50))
insert into t1 values (1, 1, 'data value one')
insert into t1 values (1, 1, 'data value one')
insert into t1 values (1, 2, 'data value two')

1. 첫 단계는 중복된 기본 키 값이 있는 행을 확인하는 것입니다.
SELECT col1, col2, count(*) FROM t1 GROUP BY col1, col2 HAVING count(*)

결과값이 1 이상일 경우 중복값이 있음을 의미합니다.

중복 PK 값의 집합이 많지 않은 경우 가장 좋은 방법은 이들 집합을 수동으로 하나씩 삭제하는 것입니다.

예를 들면 다음과 같습니다.

set rowcount 1 delete from t1 where col1=1 and col2=1

rowcount 값은 주어진 키 값의 중복 수에서 1을 뺀 값(n-1)이어야 합니다. 이 예에서는 2개의 중복이 있으므로 rowcount가 1로 설정됩니다. col1/col2 값은 위의 GROUP BY 쿼리 결과에서 가져온 것입니다. GROUP BY 쿼리가 여러 행을 반환하는 경우 "set rowcount" 쿼리를 각 행에 대해 한 번씩 실행해야 합니다. 이를 실행할 때마다 rowcount를 특정 PK 값의 중복 수에서 1을 뺀 값(n-1)으로 설정합니다.

행을 삭제하기 전에 행 전체가 중복인지 확인해야 합니다. 가능성이 희박하기는 하지만 PK 값이 중복되고 행 전체는 중복되지 않을 수 있습니다. 이것의 예로 기본 키가 사원 번호인 테이블에 번호는 같지만 각각 고유한 속성을 갖는 두 명의 다른 사람(또는 행)이 있는 경우를 들 수 있습니다. 이러한 경우 중복 키로 인해 행에 유효한 고유 데이터가 온 것일 수도 있습니다. 이 데이터는 나중에 조사 및 조정할 수 있도록 삭제 전에 복사해 놓고 보존해야 합니다.

테이블에 서로 다른 중복 PK 값의 집합이 많은 경우 이들 집합을 하나씩 제거하는 것은 너무 시간 낭비일 수 있습니다. 이러한 경우 다음 절차를 사용할 수 있습니다.

먼저, 위의 GROUP BY 쿼리를 실행하여 중복 PK 값의 집합 수와 각 집합의 중복 수를 파악합니다. 중복 키 값을 선택하여 보관 테이블에 넣습니다. 예를 들면 다음과 같습니다.

SELECT col1, col2, col3=count(*) INTO holdkey
FROM t1 GROUP BY col1, col2
HAVING count(*)

중복 행을 선택하여 보관 테이블에 넣고 처리 중인 중복을 제거합니다. 예를 들면 다음과 같습니다.

SELECT DISTINCT t1.* INTO holddups
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1 AND t1.col2 = holdkey.col2

이 시점에서 holddups 테이블에 고유한 PK가 있어야 하지만 위의 SSN 예에서와 같이 t1에 중복 PK와 고유한 행이 동시에 있는 경우에는 이 테이블의 PK가 고유하지 않게 됩니다. holddups의 각 키가 고유한지, 중복 키와 고유 행이 동시에 존재하지 않는지 확인하십시오. 중복 키와 고유 행이 같이 존재하는 경우에는 일단 작업을 중단하고 주어진 중복 키 값을 보관할 행을 조정해야 합니다. 예를 들어, 아래 쿼리는

SELECT col1, col2, count(*)
FROM holddups
GROUP BY col1, col2

각 행에 대해 1의 개수를 반환해야 합니다. 쿼리가 각 행에 대해 1의 개수를 반환하면 아래의 5단계로 갑니다. 그렇지 않은 경우에는 중복 키와 고유 행이 같이 존재하는 것이므로 저장할 행을 결정해야 합니다. 이를 위해 대개 행을 삭제하거나 이 행에 대한 고유 키 값을 새로 만듭니다. holddups 테이블의 이러한 각 중복 PK에 대해 이들 절차 중 적절한 방법을 사용하십시오. 원본 테이블에서 중복 행을 삭제합니다. 예를 들면 다음과 같습니다.

DELETE t1 FROM t1, holdkey
WHERE t1.col1 = holdkey.col1 AND t1.col2 = holdkey.col2

고유 행을 다시 원래 테이블에 넣습니다. 예를 들면 다음과 같습니다.

INSERT t1 SELECT * FROM holddups


출처 : 데브피아

댓글 없음:

댓글 쓰기

가장 많이 본 글