Избегайте дубликатов в запросе 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, основанных на некоторых условиях.

Ответ 1

Использование 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 менее эффективен. Смотрите эту ссылку для более подробной информации.

Ответ 2

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

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

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

Ответ 3

У меня была аналогичная проблема, ключевое слово DISTINCT работает с магией:

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

Ответ 4

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

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

Ref.: index_option

Ответ 5

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

Из SQL-сервера щелкните правой кнопкой мыши по дизайну таблицы, выберите

Выберите столбцы, которые не будут повторяться, затем введите Unique Key

Ответ 6

Я недавно столкнулся с той же проблемой...
Вот что у меня работало в MS SQL server 2017...
Первичный ключ должен быть установлен на идентификатор в таблице 2...
Столбцы и свойства столбцов должны быть одинаковыми для обеих таблиц. Это будет работать при первом запуске скрипта ниже. Дубликат идентификатора в таблице 1 не будет вставлен...

Если вы запустите его во второй раз, вы получите

Нарушение ограничения PRIMARY KEY

Это код:

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

Ответ 7

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

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

Ответ 8

Достаточно простого DELETE до INSERT:

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

Переключение Table1 на Table2 зависимости от того, какой Id таблицы и name пары вы хотите сохранить.