2010-03-25 43 views
73

Tôi có hai bảng sau:Tránh các bản sao ở INSERT INTO truy vấn SELECT trong SQL Server

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

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

tôi cần phải chèn dữ liệu từ Table1 để Table2. Tôi có thể sử dụng cú pháp sau:

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

Tuy nhiên, trong trường hợp của tôi, ID trùng lặp có thể tồn tại trong Table2 (trong trường hợp của tôi, nó chỉ là "1") và tôi không muốn sao chép đó một lần nữa như rằng sẽ ném một lỗi.

tôi có thể viết một cái gì đó như thế này:

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 

Có cách nào tốt hơn để làm điều này mà không sử dụng IF - ELSE? Tôi muốn tránh hai tuyên bố INSERT INTO-SELECT dựa trên một số điều kiện.

Trả lời

145

Sử dụng 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) 

Sử dụng 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) 

Sử dụng 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 

Trong số ba lựa chọn, LEFT JOIN/IS NULL là kém hiệu quả. Xem this link for more details.

+3

Ju st một làm rõ trên phiên bản không tồn tại, bạn sẽ cần một WITH (HOLDLOCK) gợi ý hoặc không có khóa sẽ được thực hiện (vì không có hàng để khóa!) để một luồng khác có thể chèn hàng dưới bạn. – IDisposable

+1

Thú vị, bởi vì tôi luôn tin rằng tham gia nhanh hơn các lựa chọn phụ. Có lẽ đó là cho chỉ tham gia thẳng, và không áp dụng cho tham gia trái. – Duncan

+1

Duncan, việc tham gia thường nhanh hơn khi bỏ chọn khi chúng là các truy vấn con tương quan. Nếu bạn có truy vấn phụ trong danh sách lựa chọn, thì việc nối sẽ thường nhanh hơn. – HLGEM

19

Trong MySQL bạn có thể làm điều này:

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

Liệu SQL Server có bất cứ điều gì tương tự?

+4

+1 để giáo dục tôi về điều này. Cú pháp rất đẹp. Chắc chắn ngắn hơn và tốt hơn so với cái tôi đã sử dụng. Thật không may Sql server không có điều này. –

+12

Không hoàn toàn đúng. Khi bạn tạo một chỉ mục duy nhất, bạn có thể đặt nó thành "bỏ qua các bản trùng lặp", trong trường hợp đó SQL Server sẽ bỏ qua bất kỳ nỗ lực nào để thêm một bản sao. – IamIC

+1

Và SQL Server vẫn không thể ... thảm hại. –

3

Sử dụng ignore Duplicates trên chỉ số duy nhất as suggested by IanC here là giải pháp của tôi cho một vấn đề tương tự, tạo ra các chỉ mục với Option WITH IGNORE_DUP_KEY

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

Ref .: index_option

6

Tôi chỉ có một vấn đề tương tự, DISTINCT từ khóa hoạt động ma thuật:

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

Trừ khi tôi hoàn toàn hiểu lầm bạn, điều này sẽ hoạt động nếu bạn có bản sao trong tập hợp bạn đang chèn _from_. Nó sẽ không, tuy nhiên, giúp đỡ nếu các thiết lập bạn đang chèn từ có thể là bản sao của dữ liệu đã có trong bảng 'chèn vào'. – FreeMan

2

Từ SQL Server, bạn có thể đặt Unique key chỉ mục trên bảng cho (Cột mà cần phải là duy nhất)

From sql server right click on the table design select Indexes/Keys

Select column(s) that will be not duplicate , then type Unique Key

0

Một chút chủ đề tắt, nhưng nếu bạn muốn di chuyển dữ liệu vào một bảng mới, và các bản sao có thể là trong gốc bảng, và cột có thể nhân đôi không phải là một id, một GROUP BY sẽ làm:

INSERT INTO TABLE_2 
(name) 
    SELECT t1.name 
    FROM TABLE_1 t1 
    GROUP BY t1.name 
Các vấn đề liên quan