ver - stored procedure sql tutorial
Insertar SQL Server si no existe (8)
Quiero insertar datos en mi tabla, ¡pero solo inserto que no existe en mi DB!
aquí está mi código:
ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
(@_DE nvarchar(50),
@_ASSUNTO nvarchar(50),
@_DATA nvarchar(30) )
AS
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
VALUES (@_DE, @_ASSUNTO, @_DATA)
WHERE NOT EXISTS ( SELECT * FROM EmailsRecebidos
WHERE De = @_DE
AND Assunto = @_ASSUNTO
AND Data = @_DATA);
END
Y el error es:
Msg 156, nivel 15, estado 1, correos electrónicos de procedimientoRecebidosInsert, línea 11
Sintaxis incorrecta cerca de la palabra clave ''WHERE''.
Dependiendo de su versión (2012?) De SQL Server además de IF EXISTS, también puede usar MERGE como MERGE :
ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
( @_DE nvarchar(50)
, @_ASSUNTO nvarchar(50)
, @_DATA nvarchar(30))
AS BEGIN
MERGE [dbo].[EmailsRecebidos] [Target]
USING (VALUES (@_DE, @_ASSUNTO, @_DATA)) [Source]([De], [Assunto], [Data])
ON [Target].[De] = [Source].[De] AND [Target].[Assunto] = [Source].[Assunto] AND [Target].[Data] = [Source].[Data]
WHEN NOT MATCHED THEN
INSERT ([De], [Assunto], [Data])
VALUES ([Source].[De], [Source].[Assunto], [Source].[Data]);
END
El comando INSERT
no tiene una cláusula WHERE
; tendrás que escribirlo así:
ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
(@_DE nvarchar(50),
@_ASSUNTO nvarchar(50),
@_DATA nvarchar(30) )
AS
BEGIN
IF NOT EXISTS (SELECT * FROM EmailsRecebidos
WHERE De = @_DE
AND Assunto = @_ASSUNTO
AND Data = @_DATA)
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
VALUES (@_DE, @_ASSUNTO, @_DATA)
END
END
Hice lo mismo con SQL Server 2012 y funcionó
Insert into #table1 With (ROWLOCK) (Id, studentId, name)
SELECT ''18769'', ''2'', ''Alex''
WHERE not exists (select * from #table1 where Id = ''18769'' and studentId = ''2'')
Para aquellos que buscan la manera más rápida , recientemente encontré estos puntos de referencia donde aparentemente el uso de "INSERT SELECT ... EXCEPT SELECT ..." resultó ser el más rápido para 50 millones de registros o más.
Aquí hay un código de muestra del artículo (el tercer bloque de código fue el más rápido):
INSERT INTO #table1 (Id, guidd, TimeAdded, ExtraData)
SELECT Id, guidd, TimeAdded, ExtraData
FROM #table2
WHERE NOT EXISTS (Select Id, guidd From #table1 WHERE #table1.id = #table2.id)
-----------------------------------
MERGE #table1 as [Target]
USING (select Id, guidd, TimeAdded, ExtraData from #table2) as [Source]
(id, guidd, TimeAdded, ExtraData)
on [Target].id =[Source].id
WHEN NOT MATCHED THEN
INSERT (id, guidd, TimeAdded, ExtraData)
VALUES ([Source].id, [Source].guidd, [Source].TimeAdded, [Source].ExtraData);
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT id, guidd, TimeAdded, ExtraData from #table2
EXCEPT
SELECT id, guidd, TimeAdded, ExtraData from #table1
------------------------------
INSERT INTO #table1 (id, guidd, TimeAdded, ExtraData)
SELECT #table2.id, #table2.guidd, #table2.TimeAdded, #table2.ExtraData
FROM #table2
LEFT JOIN #table1 on #table1.id = #table2.id
WHERE #table1.id is null
Podría usar el comando GO. Eso reiniciará la ejecución de sentencias SQL después de un error. En mi caso, tengo unas 1000 declaraciones INSERT, donde ya existen un puñado de esos registros en la base de datos, pero no sé cuáles. Descubrí que después de procesar unos 100, la ejecución simplemente se detiene con un mensaje de error que no puede INSERTAR porque el registro ya existe. Muy molesto, pero poner un GO resolvió esto. Puede que no sea la solución más rápida, pero la velocidad no era mi problema.
GO
INSERT INTO mytable (C1,C2,C3) VALUES(1,2,3)
GO
INSERT INTO mytable (C1,C2,C3) VALUES(4,5,6)
etc ...
Pruebe el código siguiente
ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
(@_DE nvarchar(50),
@_ASSUNTO nvarchar(50),
@_DATA nvarchar(30) )
AS
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
select @_DE, @_ASSUNTO, @_DATA
EXCEPT
SELECT De, Assunto, Data from EmailsRecebidos
END
Yo usaría una fusión:
create PROCEDURE [dbo].[EmailsRecebidosInsert]
(@_DE nvarchar(50),
@_ASSUNTO nvarchar(50),
@_DATA nvarchar(30) )
AS
BEGIN
with data as (select @_DE as de, @_ASSUNTO as assunto, @_DATA as data)
merge EmailsRecebidos t
using data s
on s.de = t.de
and s.assunte = t.assunto
and s.data = t.data
when not matched by target
then insert (de, assunto, data) values (s.de, s.assunto, s.data);
END
en lugar de debajo del código
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
VALUES (@_DE, @_ASSUNTO, @_DATA)
WHERE NOT EXISTS ( SELECT * FROM EmailsRecebidos
WHERE De = @_DE
AND Assunto = @_ASSUNTO
AND Data = @_DATA);
END
reemplazar con
BEGIN
IF NOT EXISTS (SELECT * FROM EmailsRecebidos
WHERE De = @_DE
AND Assunto = @_ASSUNTO
AND Data = @_DATA)
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
VALUES (@_DE, @_ASSUNTO, @_DATA)
END
END
Actualizado: (gracias a @Marc Durdin por señalar)
Tenga en cuenta que a una carga alta, esto a veces fallará, porque una segunda conexión puede pasar la prueba IF NOT EXISTS antes de que la primera conexión ejecute el INSERT, es decir, una condición de carrera. Consulte .com/a/3791506/1836776 para obtener una buena respuesta sobre por qué incluso el ajuste en una transacción no resuelve esto.