필터링 된 고유 인덱스는 훌륭한 아이디어이지만 WHERE identity_column > <current value>
조건 을 사용하든 관계없이 사소한 단점이 있습니다 WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
첫 번째 방법을 사용하면 향후에도 기존 (현재) 데이터의 복제본으로 중복 데이터를 삽입 할 수 있습니다. 예를 들어, 이제로 행이 하나만 CompanyName = 'Software Inc.'
있는 경우 인덱스는 회사 이름이 같은 행을 하나 더 삽입하는 것을 금지하지 않습니다. 두 번 시도하면 금지됩니다.
두 번째 접근 방식을 사용하면 개선 사항이 있으므로 위의 방법은 효과가 없습니다 (좋은). 그러나 여전히 더 많은 복제본 또는 기존 복제본을 삽입 할 수 있습니다. 예를 들어,로 행이 두 개 이상인 CompanyName = 'DoubleData Co.'
경우 인덱스는 회사 이름이 같은 행을 하나 이상 삽입하는 것을 금지하지 않습니다. 두 번 시도하면 금지됩니다.
(업데이트) 모든 중복 이름에 대해 제외 목록에서 하나의 ID를 유지하는 경우 수정할 수 있습니다. 위의 예와 같이 duplicate CompanyName = DoubleData Co.
와 IDs를 가진 4 개의 행이있는 4,6,8,9
경우 제외 목록에는 이러한 ID 중 3 개만 있어야합니다.
두 번째 방법을 사용하면 SQL-Server 가 필터링 된 인덱스 NOT IN
의 WHERE
일부 에서 연산자를 지원하지 않는 것처럼 보이기 때문에 번거로운 조건이 있습니다 (처음에 얼마나 많은 복제본이 있는지에 따라 얼마나 번거로운 지에 따라 다름) . SQL-Fiddle을 참조하십시오 . 대신 수백 개의 중복 이름이있는 경우 그러한 조건에 효율성에 영향을 미치는지 확실하지 않은 WHERE (CompanyID NOT IN (3,7,4,6,8,9))
것과 같은 WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
것을 가져야합니다.
@Alex Kuznetsov와 유사한 또 다른 솔루션은 다른 열을 추가하고 순위 번호로 채우고이 열을 포함하여 고유 색인을 추가하는 것입니다.
ALTER TABLE Company
ADD Rn TINYINT DEFAULT 1;
UPDATE x
SET Rn = Rnk
FROM
( SELECT
CompanyID,
Rn,
Rnk = ROW_NUMBER() OVER (PARTITION BY CompanyName
ORDER BY CompanyID)
FROM Company
) x ;
CREATE UNIQUE INDEX CompanyName_UQ
ON Company (CompanyName, Rn) ;
그런 다음 DEFAULT 1
속성과 고유 인덱스로 인해 이름이 중복 된 행을 삽입 할 수 없습니다 . 이것은 여전히 100 % 바보가 아닙니다 (알렉스가있는 동안). 명령문에 Rn
명시 적으로 설정되어 INSERT
있거나 Rn
값이 악의적으로 업데이트 된 경우에도 중복이 계속 발생합니다 .
SQL- 피들 -2