SQL Server Insert if not exist
我想在表中插入数据,但只插入数据库中不存在的数据!
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
错误是:
Msg 156, Level 15, State 1, Procedure EmailsRecebidosInsert, Line 11
Incorrect syntax near the keyword 'WHERE'.
号
而不是低于代码
1 2 3 4 5 6 7 8 | 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 |
号
替换为
1 2 3 4 5 6 7 8 9 10 | 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 |
更新:(感谢@marc durdin指点)
请注意,在高负载下,这有时仍然会失败,因为在第一个连接执行插入之前,第二个连接可以通过if not exists测试,即竞争条件。请参阅stackoverflow.com/a/3791506/1836776,了解为什么即使在事务中包装也不能解决这个问题。
对于那些寻找最快方法的人,我最近遇到了这些基准,其中显然使用了"insert select…"除了选择…"结果是5000万条或更多记录中最快的。
以下是本文中的一些示例代码(第三块代码最快):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 |
。
我将使用合并:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
。
尝试以下代码
1 2 3 4 5 6 7 8 9 10 11 | 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 |
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
我对SQL Server 2012也做了同样的事情,它起到了作用。
1 2 3 | INSERT INTO #table1 WITH (ROWLOCK) (Id, studentId, name) SELECT '18769', '2', 'Alex' WHERE NOT EXISTS (SELECT * FROM #table1 WHERE Id = '18769' AND studentId = '2') |
取决于您的版本(2012年?)对于SQL Server,除了if exists之外,还可以使用merge,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
如下面的代码所述:执行下面的查询并验证您自己(它们是自解释的)
1 2 3 4 5 6 7 | CREATE TABLE `table_name` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `address` VARCHAR(255) NOT NULL, `tele` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; |
插入记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | INSERT INTO TABLE_NAME (name, address, tele) SELECT * FROM (SELECT 'Nazir', 'Kolkata', '033') AS tmp WHERE NOT EXISTS ( SELECT name FROM TABLE_NAME WHERE name = 'Nazir' ) LIMIT 1; Query OK, 1 ROW affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 SELECT * FROM `table_name`; +----+--------+-----------+------+ | id | name | address | tele | +----+--------+-----------+------+ | 1 | Nazir | Kolkata | 033 | +----+--------+-----------+------+ |
。
现在,再次尝试插入相同的记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | INSERT INTO TABLE_NAME (name, address, tele) SELECT * FROM (SELECT 'Nazir', 'Kolkata', '033') AS tmp WHERE NOT EXISTS ( SELECT name FROM TABLE_NAME WHERE name = 'Nazir' ) LIMIT 1; Query OK, 0 ROWS affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 +----+--------+-----------+------+ | id | name | address | tele | +----+--------+-----------+------+ | 1 | Nazir | Kolkata | 033 | +----+--------+-----------+------+ |
号
插入其他记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | INSERT INTO TABLE_NAME (name, address, tele) SELECT * FROM (SELECT 'Santosh', 'Kestopur', '044') AS tmp WHERE NOT EXISTS ( SELECT name FROM TABLE_NAME WHERE name = 'Santosh' ) LIMIT 1; Query OK, 1 ROW affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 SELECT * FROM `table_name`; +----+--------+-----------+------+ | id | name | address | tele | +----+--------+-----------+------+ | 1 | Nazir | Kolkata | 033 | | 2 | Santosh| Kestopur | 044 | +----+--------+-----------+------+ |
号
你可以使用go命令。这将在出错后重新启动SQL语句的执行。在我的例子中,我有一些1000个insert语句,其中一些记录已经存在于数据库中,我只是不知道哪些记录。我发现,在处理了几百个之后,执行只会停止,并显示一条错误消息,因为记录已经存在,所以无法插入。挺烦人的,不过一走了之就解决了这个问题。这可能不是最快的解决方案,但速度不是我的问题。
1 2 3 4 5 | GO INSERT INTO mytable (C1,C2,C3) VALUES(1,2,3) GO INSERT INTO mytable (C1,C2,C3) VALUES(4,5,6) etc ... |
。