SQL ServerのINSERT INTO SELECTクエリでの重複を避ける


109

次の2つのテーブルがあります。

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ある条件に基づく2つのステートメントを避けたいです。

回答:


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

3つのオプションのうち、LEFT JOIN/IS NULL効率は低くなります。詳細については、このリンクを参照してください


9
NOT EXISTSバージョンを明確にすると、WITH(HOLDLOCK)ヒントが必要になるか、ロックが取得されないため(ロックする行がないため)、別のスレッドがその行を挿入できます。
IDisposable

3
興味深いことに、私は常にサブセレクトよりも参加が速いと信じていました。おそらく、これはストレート結合のみであり、左結合には適用されません。
ダンカン

1
Duncan、結合は、相関サブクエリの場合、サブセレクトよりも結合が高速になることがよくあります。選択リストにサブクエリがある場合、結合の方が高速になることがよくあります。
HLGEM 2010年

9
NOT EXISTS複合主キーでは特に便利ですが、機能しNOT INません
tomash

1
@OMGPonies-詳細へのリンクが機能していないようです。役に立つかもしれない別のものがありますか?
FreeMan、2017年

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はまだできません...哀れです。
スマックジャック

1
SQL Serverはまだできないのですか?
Ingus

8

私は同様の問題を抱えていましたが、DISTINCTキーワードは魔法のように機能します。

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

21
あなたが挿入しているセットで重複している場合、私は完全に誤解します、これは動作しますしない限り、からを。ただし、挿入元のセットが既にinsert intoテーブルにあるデータの複製である場合は役に立ちません。
FreeMan 2017年

5

私は最近同じ問題に直面していました...
MS SQLサーバー2017で私のために働いたものはここにあります...
主キーは表2のIDに設定する必要が
あります... 列と列のプロパティはもちろん両方の間で同じでなければなりませんテーブル。これは、以下のスクリプトを初めて実行したときに機能します。表1の重複IDは挿入されません...

2回目に実行すると、

PRIMARY KEY制約エラーの違反

これはコードです:

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

4

ここIanCによって提案さignore Duplicatesれた一意のインデックスで使用することは、同様の問題に対する私の解決策であり、オプションでインデックスを作成しました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サーバーからテーブルデザインを右クリックし、[インデックス/キー]を選択します。

重複しない列を選択してから、一意のキーを入力してください


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、

@Andir何らかの理由で「Table2」が「INSERT」の後にドロップされないようにする必要がある場合は、他のメソッドを使用しますが、これはOPが要求したことを達成するための完全に有効な方法です。
Sacro

1
有効ですが、トランザクションがなければ遅くなり、破損する可能性があります。この方法を使用する場合は、トランザクションでラップしてください。
MC9000
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.