2010-03-25 6 views
73

У меня есть следующие две таблицы:Избегайте дубликатов в INSERT INTO SELECT, запрос в SQL Server

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 

Однако, в моем случае, повторяющиеся идентификаторы могут существовать в 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, основанных на некоторых условиях.

ответ

145

Использование 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 менее эффективен. См. this link for more details.

+3

Ju Если вы хотите уточнить версию NOT EXISTS, вам понадобится подсказка WITH (HOLDLOCK) или никаких блокировок (потому что нет блокировок!), чтобы другой поток мог вставить строку под вас. – IDisposable

+1

Интересно, потому что я всегда считал, что присоединение будет быстрее, чем подвыборы. Возможно, это только для прямого соединения и не применимо к левым объединениям. – Duncan

+1

Дункан, соединение часто быстрее, чем подзапросы, когда они связаны с подзапросами. Если у вас есть подзапрос в списке выбора, соединение часто будет быстрее. – HLGEM

19

В MySQL вы можете сделать это:

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

ли SQL Server есть что-нибудь подобное?

+4

+1 для обучения меня этому. Очень красивый синтаксис. Определенно короче и лучше, чем тот, который я использовал. К сожалению, Sql-сервер этого не имеет. –

+12

Не совсем верно. Когда вы создаете уникальный индекс, вы можете установить его «игнорировать дубликаты», и в этом случае SQL Server будет игнорировать любые попытки добавить дубликат. – IamIC

+1

И SQL Server все еще не может ... жалко. –

3

Использование ignore Duplicates на уникальном индексе as suggested by IanC here было мое решение по аналогичному вопросу, создавая индекс с опцией WITH IGNORE_DUP_KEY

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

Ref .: index_option

6

Я просто имел подобную проблему, неповторяющиеся ключевое слово работает магия:

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

Если я полностью не понимаю вас, это будет работать, если у вас есть дубликаты в наборе, который вы вставляете _from_. Тем не менее, это не поможет, если набор, который вы вставляете, может быть дублированием данных уже в таблице 'insert into'. – FreeMan

2

С SQL Server вы можете установить Уникальный ключ индекс на столе (Столбцы, который должен быть уникальным)

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

Немного не по теме, но если вы хотите перенести данные в новую таблицу, и возможные дубликаты в исходной таблицы, а столбец, возможно, дублируется не является идентификатор, GROUP BY будет делать:

INSERT INTO TABLE_2 
(name) 
    SELECT t1.name 
    FROM TABLE_1 t1 
    GROUP BY t1.name 
Смежные вопросы