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

时间:2010-07-16 21:10:02

标签: sql sql-server tsql

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

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

4 个答案:

答案 0 :(得分: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);

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

Link to plan images for first run

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

Link to plan images for second run

测试脚本

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

答案 1 :(得分:12)

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

答案 2 :(得分:1)

简而言之,您需要一个保证为您提供返回一行的表:

Insert dbo.Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3',....
From Information_Schema.Tables
Where Table_Schema = 'dbo'
    And Table_Name = 'Table'
    And Not Exists  (
                    Select 1
                    From dbo.Table
                    Where Col1 = 'Foo'
                        And Col2 = 'Bar'
                        And ....
                    )

我也看到了野外的这种变化:

Insert Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3'....
From    (
        Select 1 As Num
        ) As Z
Where Not Exists    (
                    Select 1
                    From Table
                    Where Col1 = Foo
                        And Col2 = Bar
                        And ....
                    ) 

答案 3 :(得分:0)

我必须投票赞成添加CONSTRAINT。这是最简单,最强大的答案。我的意思是,看看其他答案有多复杂,我会说他们更难做到(并保持正确)。

缺点:[1]通过阅读代码,在DB [2]中强制执行唯一性并不明显,客户端代码必须知道捕获异常。换句话说,那个追随你的家伙可能会想知道“这是怎么回事?”

除此之外:我曾经担心抛出/捕获异常是一个性能损失,但我做了一些测试(在SQL Server 2005上)并且它并不重要。