我必须在包含以下列的表格中插入值:Id
MasterId
ZipCode
Locality
Value
,CreatedTime
,{{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
尚未更改的位置。
答案 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