Уникайте дублікатів у запиті INSERT INTO SELECT на SQL Server


109

У мене є дві наступні таблиці:

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тверджень, заснованих на якійсь умові.

Відповіді:


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

З трьох варіантів LEFT JOIN/IS NULL- менш ефективний. Дивіться це посилання для отримання більш детальної інформації .


9
Просто роз’яснення щодо версії NOT EXISTS, вам знадобиться підказка З (HOLDLOCK), інакше не буде зроблено блокування (оскільки немає рядків для блокування!), Щоб інша нитка могла вставити рядок під вами.
Ідентифікаційний номер

3
Цікаво, адже я завжди вважав, що приєднання буде швидше, ніж суб-вибір. Можливо, це стосується лише прямих з'єднань, а не стосується лівих з'єднань.
Дункан

1
Дункан, приєднання часто швидше, ніж підселектори, коли вони співвіднесені підзапити. Якщо у списку вибору є запит, з'єднання часто буде швидшим.
HLGEM

9
NOT EXISTSособливо корисний із складеним первинним ключем, NOT INтоді не вийде
tomash

1
@OMGPonies - ваше посилання для отримання додаткової інформації здається мертвим. Чи є у вас інший, який може бути корисним?
FreeMan

36

У MySQL ви можете зробити це:

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

Чи є у SQL Server щось подібне?


5
+1 для того, щоб мене навчити цьому. Дуже приємний синтаксис. Однозначно коротше і краще, ніж те, що я використовував. На жаль, сервер Sql цього не має.
Ашиш Гупта,

13
Не зовсім вірно. Коли ви створюєте унікальний індекс, ви можете встановити його на "ігнорувати дублікати", і в цьому випадку SQL Server ігнорує будь-які спроби додати дублікат.
IamIC

2
І SQL Server все ще не може ... жалюгідний.
Smack Jack

1
Так що SQL Server все ще не може?
Ingus

8

У мене просто була подібна проблема, ключове слово DISTINCT працює магічно:

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

21
Хіба я абсолютно неправильно зрозуміти вас, це буде працювати , якщо у вас є дублікати в наборі ви вставляєте з . Однак це не допоможе, якщо набір, з якого ви вставляєте, може бути копіями даних, які вже є в insert intoтаблиці.
FreeMan

5

Нещодавно я зіткнувся з тією ж проблемою ...
Ось що мені працювало на MS SQL сервері 2017 року ...
Первинний ключ повинен бути встановлений для ідентифікатора в таблиці 2 ...
Стовпці та властивості стовпців повинні бути однаковими між обома столи. Це буде працювати при першому запуску нижчезазначеного сценарію. Дублікат ідентифікатора в таблиці 1 не вставлятиме ...

Якщо ви запустите його вдруге, ви отримаєте

Порушення ПЕРШОЇ КЛЮЧНОЇ помилки обмеження

Це код:

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


4

З SQL Server можна встановити на таблиці унікальний індекс ключа (Стовпці, які повинні бути унікальними)

На сервері sql правою кнопкою миші на дизайні таблиці виберіть «Індекси / ключі»

Виберіть стовпчик (и), який не буде повторюваним, а потім введіть Унікальний ключ


1

Трохи поза темою, але якщо ви хочете перенести дані до нової таблиці, а можливі дублікати знаходяться в початковій таблиці , а стовпець, можливо, дублюється не є ідентифікатором, 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

Перемикання Table1в Table2залежності від того , таблиці Idі nameсполучення ви хочете зберегти.


3
Будь ласка, не робіть цього. Ви в основному говорите, "що б я не мав даних, ми просто вставимо ці нові дані!"
Андір

@Andir Якщо з якоїсь причини "Table2" після "INSERT" не слід скидати, то використовуйте інші методи, але це абсолютно вірний спосіб досягти того, про що попросила ОП.
Сакро

1
Дійсний, але, безумовно, повільніше і потенційно корумпований без трансакції. Якщо ви йдете цим маршрутом, загорніть у TRANSaction.
MC9000
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.