128 votes

Sql Server - INSERT INTO SELECT pour éviter les doublons

J'ai les deux tableaux suivants:-

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

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

J'ai besoin d'insérer des données de la Table1 à la Table2 et je peux utiliser la sytaxe suivante pour cela :-.

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

Cependant, dans mon cas, des doublons d'Ids peuvent exister dans Table2 (dans mon cas, c'est juste "1") et je ne veux pas les recopier car cela entraînerait une erreur.

Je peux écrire quelque chose comme ceci :-

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

Existe-t-il une meilleure façon de procéder sans utiliser IF - ELSE ? Je veux éviter deux instructions INSERT INTO-SELECT basées sur une certaine condition.

Toute aide est appréciée.

247voto

OMG Ponies Points 144785

Utilisation de 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)

Utilisation de 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)

Utilisation de 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

Parmi ces trois options, la LEFT JOIN/IS NULL est moins efficace. Voir ce lien pour plus de détails .

10 votes

Juste une précision sur la version NOT EXISTS, vous aurez besoin d'un indice WITH(HOLDLOCK) ou aucun verrou ne sera pris (parce qu'il n'y a pas de lignes à verrouiller !) et un autre thread pourrait insérer la ligne sous vous.

3 votes

Intéressant, car j'ai toujours pensé que la jonction était plus rapide que les sous-sélections. Peut-être que cela ne concerne que les jointures droites et ne s'applique pas aux jointures gauches.

1 votes

Duncan, la jointure est souvent plus rapide que les sous-sélections lorsqu'il s'agit de sous-requêtes corrélées. Si la sous-requête se trouve dans la liste de sélection, la jointure est souvent plus rapide.

40voto

Duncan Points 1196

Dans MySQL, vous pouvez le faire :

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

Le serveur SQL a-t-il quelque chose de similaire ?

7 votes

+1 pour m'avoir instruit sur ce sujet. Très bonne syntaxe. Définitivement plus courte et meilleure que celle que j'utilisais. Malheureusement, Sql server ne dispose pas de cette syntaxe.

15 votes

Pas totalement vrai. Lorsque vous créez un index unique, vous pouvez le configurer pour "ignorer les doublons", auquel cas SQL Server ignorera toute tentative d'ajouter un doublon.

2 votes

Et SQL Server ne peut toujours pas... pathétique.

7voto

Hunter Bingham Points 119

Je viens d'avoir un problème similaire, le mot clé DISTINCT fonctionne à merveille :

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

29 votes

Sauf erreur de ma part, cela fonctionnera si vous avez des doublons dans le jeu que vous insérez. de . Cependant, cela ne vous aidera pas si le jeu de données que vous insérez est susceptible de dupliquer des données déjà présentes dans la base de données. insert into table.

5voto

Vishane Naicker Points 51

J'ai rencontré le même problème récemment...
Voici ce qui a fonctionné pour moi dans MS SQL server 2017...
La clé primaire doit être définie sur l'ID dans la table 2...
Les colonnes et les propriétés des colonnes doivent bien sûr être les mêmes pour les deux tables. Cela fonctionnera la première fois que vous exécuterez le script ci-dessous. L'ID dupliqué dans la table 1, ne sera pas inséré...

Si vous l'exécutez la deuxième fois, vous obtiendrez un

Erreur de violation de la contrainte PRIMARY KEY

Voici le code :

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

4voto

Tazz602 Points 51

Utilisation de ignore Duplicates sur l'indice unique comme suggéré par IanC ici était ma solution pour un problème similaire, en créant l'index avec l'option WITH IGNORE_DUP_KEY

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

Réf : option_index

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X