我需要在N:N关系表中插入很多行,但是如果某个键(IDTable1,IDTable2)存在,它将引发异常,并且不会插入其余键。
我正在尝试以这种方式插入数据:
insert into MyTable(IDTable1, IDTable2)
VALUES(1,2),
VALUES(1,3),
VALUES(2,4),
VALUES(4,5),
VALUES(5,7);
问题在于,如果存在例如(1,3),则不会插入其余键,但是我希望如果某个键存在,则忽略它并插入不存在的键。
我也尝试过用try / catch进行尝试:
begin try
insert into MyTable(IDTable1, IDTable2)
VALUES(1,2),
VALUES(1,3),
VALUES(2,4),
VALUES(4,5),
VALUES(5,7);
end try
begin catch
end catch
但是问题是一样的,我受到0行影响。
是否可以忽略现有键并插入不存在的键?
谢谢。
答案 0 :(得分:3)
一种方法是使用MERGE
;
CREATE TABLE MyTable(
IDTable1 int
, IDTable2 int
, CONSTRAINT UQ_MyTable UNIQUE (IDTable1, IDTable2)
);
INSERT INTO dbo.MyTable VALUES(1,3);
GO
MERGE dbo.MyTable AS target
USING (
VALUES
(1,2),
(1,3),
(2,4),
(4,5),
(5,7)
) AS source(IDTable1, IDTable2) ON
source.IDTable1 = target.IDTable1
AND source.IDTable2 = target.IDTable2
WHEN NOT MATCHED BY TARGET THEN
INSERT (IDTable1, IDTable2) VALUES(source.IDTable1, source.IDTable2);
GO
这也可以与INSERT...SELECT
和NOT EXISTS
一起完成:
INSERT INTO dbo.MyTable (IDTable1, IDTable2)
SELECT IDTable1, IDTable2
FROM (
VALUES
(1,2),
(1,3),
(2,4),
(4,5),
(5,7)
) AS source(IDTable1, IDTable2)
WHERE NOT EXISTS(
SELECT *
FROM dbo.MyTable as TARGET
WHERE target.IDTable1 = source.IDTable1
AND target.IDTable2 = source.IDTable2
);
编辑:
这是一个LEFT OUTER JOIN
方法:
INSERT INTO [MyTable] ([IDTable1], [IDTable2])
SELECT source.[IDTable1], source.[IDTable2]
FROM MyTable AS target
LEFT JOIN (
VALUES
(1,2),
(1,3),
(2,4),
(4,5),
(5,7)
) AS source(IDTable1, IDTable2) ON
source.[IDTable1] = target.[IDTable1]
AND source.[IDTable2] = target.[IDTable2]
WHERE target.[IDTable1] IS NULL;
GO
对于此特定的表,索引和数据,MERGE
似乎基于最少的逻辑读取而表现最佳。使用SQL Server 2017的这三种方法的STATISTCS IO结果为:
合并:
Table 'MyTable'. Scan count 0, logical reads 22, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
不存在:
Table 'MyTable'. Scan count 1, logical reads 17, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 11, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
左外联接:
Table 'MyTable'. Scan count 1, logical reads 17, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 11, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
我观察到类似的结果,但受到CLUSTERED
唯一约束。
但是,从性能的角度来看,我不会一概而论MERGE
始终是最好的方法。理想情况下,SQL Server将为语义上相同的查询生成相同的计划,尽管实际上并非总是如此。当特别关注性能时,您需要检查执行计划并使用代表性数据测试性能。
答案 1 :(得分:0)
在SQL中,您必须准备将整个列表一次性插入,而不尝试一次插入,然后移至下一个。
这应该为您解决问题。它会连接到您要插入的表中,而忽略任何找到匹配项的内容
INSERT INTO [MyTable] ([IDTable1], [IDTable2])
SELECT [IDTable1], [IDTable2]
FROM [MySource] as source
LEFT JOIN [MyTable] AS duplicates
ON source.[IDTable1] = duplicates.[IDTable1]
AND source.[IDTable2] = duplicates.[IDTable2]
WHERE duplicates.[IDTable1] IS NULL