我有一个将记录插入表中的存储过程。我在表上创建了一个唯一的键约束,以避免重复记录。
无论是否定义了唯一键约束,我使用IF()条件(在INSERT语句之前)来检查可能已存在的重复记录。
但是,我用来检查重复记录的条件语句似乎对INSERT是否执行没有影响。 - 即当提交给sproc的重复记录时,抛出“违反UNIQUE KEY约束......”异常。
以下是我的样本:
BEGIN
if
(SELECT Count(f1)
FROM table
WHERE f1 = @f1
AND f2= @f2)
<= 0
BEGIN
INSERT INTO table
(f1,f2)
VALUES
(@f1, @f2)
RETURN @@IDENTITY
END
END
我的语法有问题吗?或者,也许,我会以错误的方式解决这个问题?
答案 0 :(得分:3)
Count(field)
计算非空值
这可能与计算行数的count(*)
不同。
但我不鼓励在这里使用count
看看this question。
答案 1 :(得分:3)
如果您使用的是SQL Server 2008或更新版本,则应使用MERGE
语句:
MERGE INTO table AS t
USING (VALUES (@f1, @f2)) AS s (f1, f2)
ON s.f1 = t.f1
AND s.f2 = t.f2
WHEN NOT MATCHED BY t THEN
INSERT (f1, f2) VALUES (@f1, @f2)
答案 2 :(得分:2)
这更安全并发:
INSERT INTO table
SELECT @f1, @f2, @f3
FROM TABLE WITH (UPDLOCK, HOLDLOCK)
WHERE NOT EXISTS(SELECT NULL
FROM table
WHERE f1 = @f1
AND f2 = @f2
AND f3 = @f3)
或者,如果您想保留决策逻辑(但并发安全性较低),请使用NOT EXISTS:
IF NOT EXISTS(SELECT NULL
FROM table
WHERE f1 = @f1
AND f2 = @f2
AND f3 = @f3)
BEGIN
INSERT INTO table
(f1,f2, f3)
VALUES
(@f1, @f2, @f3)
RETURN @@SCOPE_IDENTITY
END
答案 3 :(得分:1)
感谢您输入OMG / Martin,但事实证明我的问题的根源是由于参数值为null。
具体做法是:
--sproc params
@f1 int,
@f2 nvarchar(30),
@f3 datetime = null --<<a null value will screw up the IF() condition
IF(SELECT COUNT(f1)
FROM table
WHERE f1 = @f1
AND f2 = @f2
AND f3 = @f3)
<1
BEGIN
INSERT INTO....
END
请注意,@ f3 param的默认值为null。因此,在sproc的调用者没有传递@ f3参数的情况下,即使存在匹配的@ f1,@ f2和null @ f3,IF()条件也将返回0(零)。 p>
例如:假设表格已经有
的记录f1 f2 f3
--------------
45 foo NULL
现在调用者通过发送它来激活sproc:
@ F1 = 45
@ F2 = FOO
(注意来电者未指定@ f3)
当IF()条件被触发时,它将返回0(零)。奇怪,是吗?直觉上,我认为条件会返回1,因为params与表中的现有值完全匹配。
为了使问题更加混乱(对我来说,无论如何),即使IF()成功(返回零),我收到“违反UNIQUE KEY约束......”异常。实际上,由于我认为param值与表中的现有记录完美匹配,因此抛出异常并不令我感到惊讶 - 对我而言,令人困惑的部分是为什么IF()条件与违反异常相矛盾的原因
顺便说一句,OMGPonies,我尝试使用你的建议(EXISTS),并出现相同的症状。显然,NULL因子会让事情变得模糊。
答案 4 :(得分:0)
SET NOCOUNT ON
SELECT * FROM table
WHERE f1 = @f1
AND f2= @f2
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO table
(f1,f2)
VALUES
(@f1, @f2)
RETURN @@IDENTITY
END