只有在单个语句中不存在记录时才可以插入吗?

时间:2016-07-19 21:25:54

标签: sql sql-server sql-server-2012

我必须在包含以下列的表格中插入值:Id MasterId ZipCode Locality ValueCreatedTime,{{1 }}

这三列定义了一个唯一值:UpdatedTime MasterId ZipCode

这些列上的数据库没有唯一约束,但我需要确保2个用户无法输入相同的数据。我无法更改T-SQL数据库架构。

当前SQL:

Locality

我的SQL更改:

INSERT INTO dbo.Carrier VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE())

这些更改适用于标准用户输入,但也有一个服务同时插入许多条目。有时,此服务将尝试以多线程方式插入数千个相同的唯一行,并且SQL具有竞争条件,因为它不是一个语句。这允许在同时执行2个语句时输入重复项。

有没有办法只在单个陈述中不存在记录时插入?

我在更新时没有遇到此问题,因为我可以执行IF NOT EXISTS ( SELECT TOP 1 * FROM dbo.Carrier WHERE MasterId = ? AND ZipCode = ? AND Locality = ? ) BEGIN INSERT INTO dbo.Carrier VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE()) END 尚未更改的位置。

3 个答案:

答案 0 :(得分:6)

我会使用not exists

作为单个语句执行此操作
insert into dbo.Carrier (masterid, zipcode, locality, . . . )
    select v.*
    from (values (?, ?, ?, ... ), (?, ?, ?, ...)) v(masterid, zipcode, locality, . . .)
    where not exists (select 1
                      from dbo.Carrier c
                      where c.masterid = v.masterid and c.zipcode = v.zipcode and c.locality = v.locality
                     );

编辑:

如果要在竞争条件下保护数据库,则应该让数据库进行保护。在(masterid, zipcode, locality)上添加唯一索引/约束。然后你应该忽略任何违反约束的错误。

答案 1 :(得分:1)

MERGE statement解决方案是这样的:

MERGE INTO Carrier dst
USING (VALUES(?,?,?,...)) as src(MasterId, Zipcode, Locality,...)
ON src.MasterId=dst.MasterId AND src.Zipcode=dst.Zipcode AND src.Locality=dst.Locality
WHEN NOT MATCHED THEN INSERT (
    MasterId, Zipcode, Locality
    , ...
) VALUES (
    src.MasterId, src.Zipcode, src.Locality
    , ...
)

如果需要,您还可以让merge语句在匹配行的同时插入缺失的行时执行UPDATE。

答案 2 :(得分:0)

使用CTE和加入:

;with new_record as (
    select 1 as MasterId , 90065 as ZipCode, 1 as Locality
)
insert into Carrier(MasterId, ZipCode, Locality)
select a.MasterId, a.ZipCode, a.Locality
from new_record a
left join Carrier b
on a.MasterId = b.MasterId
    and a.ZipCode = b.ZipCode
    and a.Locality = b.Locality
where b.MasterId is null