仅当表中尚不存在记录时才插入记录

Meg*_*att 30 sql t-sql sql-server

我想知道是否有办法只在表中没有包含该记录的情况下将记录插入表中?

是否有查询会执行此操作,还是需要存储过程?

Mar*_*ith 25

你没有说什么版本的SQL Server.如果SQL Server 2008可以使用MERGE

注意:通常使用Merge进行Upsert,这是我最初认为问题的问题,但它没有WHEN MATCHED条款,只有一个WHEN NOT MATCHED条款是有效的,所以也适用于这种情况.示例用法.

CREATE TABLE #A(
 [id] [int] NOT NULL PRIMARY KEY CLUSTERED,
 [C] [varchar](200) NOT NULL)


    MERGE #A AS target
    USING (SELECT 3, 'C') AS source (id, C)
    ON (target.id = source.id)
    /*Uncomment for Upsert Semantics
       WHEN MATCHED THEN 
        UPDATE SET C = source.C */
    WHEN NOT MATCHED THEN    
        INSERT (id, C)
        VALUES (source.id, source.C);
Run Code Online (Sandbox Code Playgroud)

就执行成本而言,当要完成插入时,两者看起来大致相等......

链接到第一次运行的计划图像

但是在第二次运行时,没有插件可以完成马修的答案看起来成本更低.我不确定是否有办法改善这一点.

链接到计划第二次运行的图像

测试脚本

select * 
into #testtable
from master.dbo.spt_values

CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)


declare @name nvarchar(35)= 'zzz'
declare @number int = 50
declare @type nchar(3) = 'A'
declare @low int
declare @high int
declare @status int = 0;



MERGE #testtable AS target
USING (SELECT @name, @number, @type, @low, @high, @status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name] )
WHEN NOT MATCHED THEN    
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);

set @name = 'yyy'

IF NOT EXISTS 
    (SELECT *
    FROM #testtable
    WHERE [type] = @type AND [number] = @number and name = @name)
    BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (@name, @number, @type, @low, @high, @status);
END
Run Code Online (Sandbox Code Playgroud)

  • 问题是正确性,而不是性能.`IF NOT EXISTS(SELECT ...)INSERT`将在负载下导致重复错误,保证. (3认同)
  • @RemusRusanu - BTW [根据这篇文章](http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx)`Merge`仍然可能有问题在此区域,除非使用"HOLDLOCK". (2认同)

Mat*_*nes 12

IF NOT EXISTS 
    (SELECT {Columns} 
    FROM {Table} 
    WHERE {Column1 = SomeValue AND Column2 = SomeOtherVale AND ...}) 
INSERT INTO {Table} {Values}
Run Code Online (Sandbox Code Playgroud)

  • -1因为这是**在高负载下获得重复错误的方法.SELECT和INSERT在不同的时间运行,没有什么可以阻止两个并发线程尝试插入相同的值.由Martin发布的MERGE是一个合适的解决方案 (8认同)