SQL Server의 INSERT INTO SELECT 쿼리에서 중복 방지


109

다음 두 테이블이 있습니다.

Table1
----------
ID   Name
1    A
2    B
3    C

Table2
----------
ID   Name
1    Z

에서 Table1에 데이터를 삽입해야합니다 Table2. 다음 구문을 사용할 수 있습니다.

INSERT INTO Table2(Id, Name) SELECT Id, Name FROM Table1

그러나 제 경우에는 중복 ID가 존재할 수 있으며 Table2(제 경우에는 " 1" 일뿐 ) 오류가 발생할 수 있으므로 다시 복사하고 싶지 않습니다.

다음과 같이 작성할 수 있습니다.

IF NOT EXISTS(SELECT 1 FROM Table2 WHERE Id=1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1 
ELSE
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1 WHERE Table1.Id<>1

사용하지 않고이 작업을 수행하는 더 좋은 방법이 IF - ELSE있습니까? INSERT INTO-SELECT조건에 따라 두 가지 진술 을 피하고 싶습니다 .

답변:


201

사용 NOT EXISTS:

INSERT INTO TABLE_2
  (id, name)
SELECT t1.id,
       t1.name
  FROM TABLE_1 t1
 WHERE NOT EXISTS(SELECT id
                    FROM TABLE_2 t2
                   WHERE t2.id = t1.id)

사용 NOT IN:

INSERT INTO TABLE_2
  (id, name)
SELECT t1.id,
       t1.name
  FROM TABLE_1 t1
 WHERE t1.id NOT IN (SELECT id
                       FROM TABLE_2)

사용 LEFT JOIN/IS NULL:

INSERT INTO TABLE_2
  (id, name)
   SELECT t1.id,
          t1.name
     FROM TABLE_1 t1
LEFT JOIN TABLE_2 t2 ON t2.id = t1.id
    WHERE t2.id IS NULL

세 가지 옵션 중 LEFT JOIN/IS NULL효율성이 떨어집니다. 자세한 내용은 이 링크를 참조하십시오 .


9
NOT EXISTS 버전에 대한 설명 만 있으면 WITH (HOLDLOCK) 힌트가 필요합니다. 그렇지 않으면 잠글 행이 없기 때문에 잠금이 수행되지 않으므로 다른 스레드가 해당 행을 사용자 아래에 삽입 할 수 있습니다.
는 IDisposable

3
흥미 롭습니다. 저는 항상 결합이 하위 선택보다 더 빠르다고 믿었 기 때문입니다. 아마도 이것은 직선 조인에만 해당되며 왼쪽 조인에는 적용되지 않습니다.
Duncan

1
Duncan, 조인은 상호 관련된 하위 쿼리 일 때 하위 선택하는 것보다 더 빠릅니다. 선택 목록에 하위 쿼리가있는 경우 조인이 더 빠른 경우가 많습니다.
HLGEM

9
NOT EXISTS복합 기본 키에 특히 유용하지만 NOT IN그때는 작동하지 않습니다
tomash

1
@OMGPonies-자세한 내용에 대한 링크가 죽은 것 같습니다. 유용 할 수있는 다른 것이 있습니까?
FreeMan

36

MySQL에서는 다음을 수행 할 수 있습니다.

INSERT IGNORE INTO Table2(Id, Name) SELECT Id, Name FROM Table1

SQL Server에도 비슷한 것이 있습니까?


5
이것에 대해 나를 교육시켜 준 +1. 아주 좋은 구문. 내가 사용한 것보다 확실히 짧고 낫습니다. 불행히도 SQL 서버에는이 기능이 없습니다.
Ashish Gupta

13
완전히 사실이 아닙니다. 고유 인덱스를 만들 때 "중복을 무시"하도록 설정할 수 있습니다.이 경우 SQL Server는 중복 추가 시도를 무시합니다.
IamIC

2
그리고 SQL Server는 여전히 한심할 수 없습니다.
Smack Jack

1
그래서 SQL Server는 여전히 할 수 없습니까?
Ingus

8

비슷한 문제가 있었는데 DISTINCT 키워드가 마술처럼 작동합니다.

INSERT INTO Table2(Id, Name) SELECT DISTINCT Id, Name FROM Table1

21
당신은 삽입하고있는 집합에 중복이 있다면 나는 완전히 오해 당신이 작동하지 않는 한 에서를 . 그러나 삽입하려는 세트가 이미 insert into테이블 에있는 데이터의 중복 일 수있는 경우에는 도움이되지 않습니다 .
FreeMan

5

나는 최근에 같은 문제에 직면했다 ...
MS SQL 서버 2017에서 나를 위해 일한 것은 다음과 같다 ...
기본 키는 표 2의 ID에 설정되어야한다 ...
물론 열과 열 속성은 둘 다 동일해야한다 테이블. 아래 스크립트를 처음 실행할 때 작동합니다. 표 1의 중복 ID는 삽입되지 않습니다.

두 번째로 실행하면

PRIMARY KEY 제약 조건 위반 오류

다음은 코드입니다.

Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1

4

IanC가 제안한ignore Duplicates 고유 인덱스 사용 하여 유사한 문제에 대한 솔루션을 사용하여 Option으로 인덱스를 생성했습니다.WITH IGNORE_DUP_KEY

In backward compatible syntax
, WITH IGNORE_DUP_KEY is equivalent to WITH IGNORE_DUP_KEY = ON.

참조 : index_option


4

SQL Server 에서 테이블에 대한 고유 키 인덱스를 설정할 수 있습니다 (고유해야하는 열).

SQL Server에서 테이블 디자인을 마우스 오른쪽 버튼으로 클릭하고 인덱스 / 키를 선택합니다.

중복되지 않을 열을 선택한 다음 고유 키를 입력합니다.


1

약간 벗어난 주제이지만 데이터를 새 테이블로 마이그레이션하고 가능한 중복이 원래 테이블 에 있고 중복 가능성이있는 열이 ID가 아닌 경우 다음 GROUP BY을 수행합니다.

INSERT INTO TABLE_2
(name)
  SELECT t1.name
  FROM TABLE_1 t1
  GROUP BY t1.name

-1

간단한 DELETE전에 INSERT충분합니다.

DELETE FROM Table2 WHERE Id = (SELECT Id FROM Table1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1

보존하려는 테이블 과 페어링 Table1Table2따라 전환 합니다 .Idname


3
이러지 마세요. 당신은 기본적으로 "내가 가지고있는 데이터는 무가치하다.이 새로운 데이터를 삽입하자!"라고 말하고 있습니다.
Andir dec

@Andir 어떤 이유로 "Table2"가 "INSERT"후에 삭제되지 않아야하는 경우 다른 방법을 사용합니다. 그러나 이것은 OP가 요청한 것을 달성하는 데 완벽하게 유효한 방법입니다.
Sacro

1
유효하지만 트랜잭션 없이는 확실히 느리고 잠재적으로 손상 될 수 있습니다. 이 경로로 가면 TRANSaction으로 포장하십시오.
MC9000
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.