Hindari duplikat dalam kueri INSERT INTO SELECT di SQL Server

109

Saya memiliki dua tabel berikut:

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

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

Saya perlu memasukkan data dari Table1hingga Table2. Saya dapat menggunakan sintaks berikut:

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

Namun, dalam kasus saya, ID duplikat mungkin ada Table2(dalam kasus saya, ini hanya " 1") dan saya tidak ingin menyalinnya lagi karena itu akan menimbulkan kesalahan.

Saya bisa menulis sesuatu seperti ini:

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

Apakah ada cara yang lebih baik untuk melakukan ini tanpa menggunakan IF - ELSE? Saya ingin menghindari dua INSERT INTO-SELECTpernyataan berdasarkan beberapa kondisi.

Ashish Gupta
sumber

Jawaban:

201

Menggunakan 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)

Menggunakan 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)

Menggunakan 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

Dari ketiga pilihan tersebut, LEFT JOIN/IS NULLkurang efisien. Lihat tautan ini untuk lebih jelasnya .

OMG Ponies
sumber
9
Hanya klarifikasi pada versi TIDAK ADA, Anda memerlukan petunjuk DENGAN (HOLDLOCK) atau tidak ada kunci yang akan diambil (karena tidak ada baris untuk dikunci!) Sehingga utas lain dapat menyisipkan baris di bawah Anda.
IDisposable
3
Menarik, karena saya selalu percaya bergabung lebih cepat daripada sub-seleksi. Mungkin itu hanya untuk gabungan lurus, dan tidak berlaku untuk gabungan kiri.
Duncan
1
Duncan, penggabungan seringkali lebih cepat daripada subkueri yang berkorelasi. Jika Anda memiliki subkueri di daftar pilih, penggabungan akan sering lebih cepat.
HLGEM
9
NOT EXISTSsangat berguna dengan kunci primer komposit, NOT INtidak akan berfungsi saat itu
tomash
1
@OMGPonies - link Anda untuk lebih jelasnya sudah mati. Apakah Anda memiliki yang lain yang mungkin berguna?
FreeMan
36

Di MySQL, Anda dapat melakukan ini:

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

Apakah SQL Server memiliki kesamaan?

Duncan
sumber
5
1 untuk mendidik saya tentang ini. Sintaks yang sangat bagus. Jelas lebih pendek dan lebih baik dari yang saya gunakan. Sayangnya server Sql tidak memiliki ini.
Ashish Gupta
13
Tidak sepenuhnya benar. Saat Anda membuat indeks unik, Anda dapat mengaturnya ke "mengabaikan duplikat", dalam hal ini SQL Server akan mengabaikan upaya apa pun untuk menambahkan duplikat.
IamIC
2
Dan SQL Server masih tidak bisa ... menyedihkan.
Smack Jack
1
Jadi SQL Server masih belum bisa?
Ingus
8

Saya baru saja mengalami masalah serupa, kata kunci DISTINCT bekerja dengan ajaib:

INSERT INTO Table2(Id, Name) SELECT DISTINCT Id, Name FROM Table1
Hunter Bingham
sumber
21
Kecuali aku benar-benar salah paham Anda, ini akan bekerja jika Anda memiliki duplikat di set Anda memasukkan dari . Namun, itu tidak akan membantu jika kumpulan yang Anda sisipkan mungkin merupakan duplikat data yang sudah ada di insert intotabel.
FreeMan
5

Saya menghadapi masalah yang sama baru-baru ini ...
Inilah yang berhasil untuk saya di MS SQL server 2017 ...
Kunci utama harus ditetapkan pada ID di tabel 2 ...
Properti kolom dan kolom harus sama tentu saja antara keduanya tabel. Ini akan berfungsi saat pertama kali Anda menjalankan skrip di bawah ini. ID duplikat di tabel 1, tidak akan dimasukkan ...

Jika Anda menjalankannya untuk kedua kalinya, Anda akan mendapatkan file

Pelanggaran kesalahan kendala PRIMARY KEY

Ini kodenya:

Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1
Vishane Naicker
sumber
4

Menggunakan ignore Duplicatesindeks unik seperti yang disarankan oleh IanC di sini adalah solusi saya untuk masalah serupa, membuat indeks dengan OptionWITH IGNORE_DUP_KEY

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

Ref .: opsi_indeks

Tazz602
sumber
4

Dari SQL Server Anda dapat mengatur indeks kunci unik pada tabel untuk (Kolom yang harus unik)

Dari sql server klik kanan pada desain tabel pilih Indexes / Keys

Pilih kolom yang bukan duplikat, lalu ketik Kunci Unik

M. Salah
sumber
1

Sedikit keluar dari topik, tetapi jika Anda ingin memindahkan data ke tabel baru, dan kemungkinan duplikat ada di tabel asli , dan kolom yang mungkin digandakan bukan id, a GROUP BYakan melakukan:

INSERT INTO TABLE_2
(name)
  SELECT t1.name
  FROM TABLE_1 t1
  GROUP BY t1.name
FullStackFool
sumber
-1

Sederhana DELETEsebelum INSERTsudah cukup:

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

Switching Table1untuk Table2tergantung pada tabel Iddan namepasangan Anda ingin melestarikan.

Sacro
sumber
3
Tolong jangan lakukan ini. Anda pada dasarnya mengatakan "data apa pun yang saya miliki tidak berharga, mari kita masukkan saja data baru ini!"
Andir
@Andir Jika karena alasan tertentu "Table2" tidak boleh dijatuhkan setelah "INSERT" maka gunakan metode lain, tetapi ini adalah cara yang benar-benar valid untuk mencapai apa yang diminta OP.
Sacro
1
Valid, tetapi pasti lebih lambat dan berpotensi merusak tanpa transaksi. Jika Anda mengikuti rute ini, selesaikan TRANSaction.
MC9000