我想在我的表中插入数据,但只插入我的数据库中不存在的数据!
这是我的代码:
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
关键字'WHERE'附近的语法不正确。
答案 0 :(得分:248)
而不是代码
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
替换为
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的指点)
请注意,在高负载下,这仍然有时会失败,因为第二个连接可以在第一个连接执行INSERT之前通过IF NOT EXISTS测试,即竞争条件。请参阅stackoverflow.com/a/3791506/1836776,以获得有关为什么即使在事务中包装也无法解决此问题的良好答案。
答案 1 :(得分:54)
对于那些寻找最快方式的人,我最近came across these benchmarks显然正在使用" INSERT SELECT ... EXCEPT SELECT ..."原来是5000万或更多记录中最快的。
这里有一些文章的示例代码(第3段代码是最快的):
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
答案 2 :(得分:22)
我会使用合并:
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
答案 3 :(得分:17)
尝试以下代码
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
答案 4 :(得分:10)
INSERT
命令没有WHERE
子句 - 你必须这样写:
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
答案 5 :(得分:8)
我使用SQL SERVER 2012做了同样的事情并且它有效
Insert into #table1 With (ROWLOCK) (Id, studentId, name)
SELECT '18769', '2', 'Alex'
WHERE not exists (select * from #table1 where Id = '18769' and studentId = '2')
答案 6 :(得分:6)
除了IF EXISTS之外,您还可以使用MERGE取决于您的SQL Server版本(2012?),如下所示:
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
答案 7 :(得分:5)
不同的SQL,相同的原理。仅当不存在的子句失败时才插入
INSERT INTO FX_USDJPY
(PriceDate,
PriceOpen,
PriceLow,
PriceHigh,
PriceClose,
TradingVolume,
TimeFrame)
SELECT '2014-12-26 22:00',
120.369000000000,
118.864000000000,
120.742000000000,
120.494000000000,
86513,
'W'
WHERE NOT EXISTS
(SELECT 1
FROM FX_USDJPY
WHERE PriceDate = '2014-12-26 22:00'
AND TimeFrame = 'W')
答案 8 :(得分:1)
如以下代码中所述:执行以下查询并验证自己(它们是不言自明的)
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;
插入记录:
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 |
+----+--------+-----------+------+
现在,尝试再次插入相同的记录:
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 |
+----+--------+-----------+------+
插入其他记录:
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 |
+----+--------+-----------+------+
答案 9 :(得分:0)
您可以使用GO命令。这将在发生错误后重新启动sql语句的执行。在我的例子中,我有几个1000 INSERT语句,其中少数这些记录已存在于数据库中,我只是不知道哪些。 我发现在处理了几个100之后,执行就会停止,并显示一条错误消息,表明它已经存在而无法插入。相当讨厌,但是把GO解决了这个问题。它可能不是最快的解决方案,但速度不是我的问题。
GO
INSERT INTO mytable (C1,C2,C3) VALUES(1,2,3)
GO
INSERT INTO mytable (C1,C2,C3) VALUES(4,5,6)
etc ...
答案 10 :(得分:0)
如果您的聚集索引仅由那些字段组成,则简单,快速和可靠的选项将使用IGNORE_DUP_KEY
如果您在启用IGNORE_DUP_KEY的情况下创建聚簇索引
比您只能使用:
INSERT INTO EmailsRecebidos (De, Assunto, Data) VALUES (@_DE, @_ASSUNTO, @_DATA)
这在所有情况下都应该是安全的!