我在存储过程中有一个SQL Server更新语句,在执行过程中违反了约束,但是一旦整个更新语句完成,约束就会生效。
陈述是:
UPDATE SomeTable SET FieldA = 1 WHERE FieldB = @SomeFieldBValue;
表中的行SomeTable与引用父行的子行形成层次关系。约束确保父行不能将FieldA设置为非空值,除非所有子行都将FieldA设置为非空值。
因此,例如,让我们假设SomeTable包含以下数据:
Id | ParentId | FieldA | FieldB
-- | -------- | ------ | ------
1 | NULL | NULL | 123
2 | 1 | NULL | 123
现在,当update语句执行时,它会因约束违规而失败,因为不允许第1行将FieldA设置为非空值,除非其所有子项都将FieldA设置为非空值。
暂时禁用约束不是一个选项,因为用户没有执行此操作的权限。
答案 0 :(得分:1)
像这样的触发器会完成同样的事情吗?
create trigger ...
if exists (
select i.Id
from
inserted i left outer join inserted i2
on i2.ParentId = i.Id
group by i.Id
having not (count(i.FieldA) = 0 or count(i2.FieldA) = count(i2.Id))
) rollback;
答案 1 :(得分:0)
永远不要在SQL中使用WHILE循环,SQL是基于集合的语言,而不是程序性的。只需将父项和所有子项选入#TEMP表,更新临时表行,删除原始项并插入新项:
BEGIN TRAN
SELECT Id, ParentID, FieldA, FieldB,
INTO #TEMP1
FROM SomeTable
WHERE FieldB = SomeValue
UPDATE #TEMP1 SET FieldA = 1
DELETE SomeTable where FieldB = SomeValue
INSERT SomeTable Set ..... FROM #TEMP1
COMMIT
答案 2 :(得分:-1)
如果您无法禁用约束,我担心您无法通过单个声明执行此操作。您必须创建一个循环并按照正确的顺序手动执行更新"。
的伪代码:
Begin Transaction
Do
recordsAffected = UPDATE SomeTable
SET FieldA = 1
WHERE (FieldA IS NULL OR FieldA <> 1)
AND FieldB = @SomeFieldBValue
AND NOT EXISTS (child with FieldA set to null);
While recordsAffected > 0
Commit Transaction
将此转换为T-SQL或您选择的客户端语言留作练习。 : - )