如何按特定顺序执行SQL Server更新?

时间:2016-08-31 15:30:49

标签: sql-server database

我在存储过程中有一个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设置为非空值。

暂时禁用约束不是一个选项,因为用户没有执行此操作的权限。

3 个答案:

答案 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或您选择的客户端语言留作练习。 : - )