2010-03-25 97 views
73

Tengo las siguientes dos tablas:evitar duplicados en la consulta INSERT INTO SELECT en SQL Server

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

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

que necesito para insertar datos de Table1 a Table2. Puedo utilizar la siguiente sintaxis:

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

Sin embargo, en mi caso, podrían existir identificadores duplicados en Table2 (en mi caso, es sólo "1") y no quiero copiar de nuevo, ya que ello lanzar un error

puedo escribir algo como esto:

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 

¿Hay una mejor manera de hacer esto sin usar IF - ELSE? Quiero evitar dos declaraciones INSERT INTO-SELECT basadas en alguna condición.

Respuesta

145

Usando 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) 

Usando 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) 

Usando 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 

De las tres opciones, la LEFT JOIN/IS NULL es menos eficiente. Ver this link for more details.

+3

Ju Para una aclaración sobre la versión NO EXISTE, necesitará una sugerencia CON (HOLDLOCK) o no se tomarán bloqueos (¡porque no hay filas para bloquear!) entonces otro hilo podría insertar la fila debajo de ti. – IDisposable

+1

Interesante, porque siempre creí que unirse era más rápido que las sub-selecciones. Tal vez sea solo para uniones rectas, y no aplicable a uniones izquierdas. – Duncan

+1

Duncan, unirse es a menudo más rápido que las subsecuentes cuando son subconsultas correlacionadas. Si tiene la subconsulta en la lista de selección, una unión a menudo será más rápida. – HLGEM

19

En MySQL puede hacer esto:

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

¿El SQL Server tiene algo similar?

+4

+1 por educarme sobre esto. Muy buena sintaxis Definitivamente más corto y mejor que el que usé. Lamentablemente, el servidor Sql no tiene esto. –

+12

No es totalmente cierto. Cuando crea un índice único, puede configurarlo para "ignorar duplicados", en cuyo caso SQL Server ignorará cualquier intento de agregar un duplicado. – IamIC

+1

Y SQL Server todavía no puede ... patético. –

3

Usando ignore Duplicates en el índice único as suggested by IanC here fue mi solución para un problema similar, la creación del índice con la opción WITH IGNORE_DUP_KEY

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

Ref .: index_option

6

que acaba de tener un problema similar, el DISTINCT palabra clave funciona la magia:

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

A menos que te malinterprete totalmente, esto funcionará si tienes duplicados en el conjunto en el que estás insertando _from_. Sin embargo, no ayudará si el conjunto del que está insertando puede ser un duplicado de datos que ya está en la tabla 'insert into '. – FreeMan

2

partir de SQL Server se puede establecer una único índice clave sobre la mesa para (Las columnas que tiene que ser único)

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

Un poco fuera de tema, pero si desea migrar los datos a una nueva tabla, y los posibles duplicados están en la tabla original , y la columna posiblemente duplicado no es un id, un GROUP BY hará:

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