7

我知道 SQL 约束可以强制数据满足有效性标准。但是,诸如“学生的成绩只能在'finalized'标志为假时更新”这样的标准呢?此类更新标准是否必须由应用程序处理?

4

3 回答 3

5

简短回答:不,当 Finalized 为“真”时,SQL 约束本身不能阻止对列 Grade 的更改(但允许更改)。

几种 SQL 约束:CHECK、DEFAULT、NOT NULL、UNIQUE、主键和外键。

这些中的每一个都可以单独或组合地限制或影响列的值,但不能阻止对允许的值进行更新。特别是,这些约束都不能阻止基于先前的 Grade 和 Finalized 值对 Grade 和/或 Finalized 进行更新。

UPDATE 触发器可以执行此操作:比较 Grade 的新值和旧值,如果这些值不同并且 Finalized = 'true',则使用说明性错误消息回滚 UPDATE。

然而,应用程序可以而且应该更优雅地执行这样的“业务规则”。规则本身可以使用一些关于何时可以更改 Finalized 值的说明。例如,是否允许同时更改 Grade 和设置 Finalized = 'false'?触发逻辑可以处理这些细节,并且将其安装为故障保护是合理的,同时在应用程序的某处(前端/中间件/后端)中明确显示规则。

于 2011-07-08T02:38:04.943 回答
4

触发器、约束和附加列。

从头开始:

  1. 附加列存储要“固定”的值:

    ALTER TABLE ADD SavedGrade int
    
  2. 约束限制了Grade列的变化:

    ALTER TABLE Students
    ADD CONSTRAINT CK_Grade CHECK (Finalised = 'false' OR Grade = SavedGrade)
    
  3. Grade列更新时,触发器会更新附加列(以下适用于 SQL Server):

    CREATE TRIGGER StudentsFinaliseGrade
    ON Students AFTER INSERT, UPDATE
    AS
    IF UPDATE(Grade)
      UPDATE Students
      SET SavedGrade = i.Grade
      FROM inserted i
      WHERE i.ID = Students.ID
        AND i.Grade <> i.SavedGrade
    

所以,只要Finalised = 'false'Grade列就可以改变。更改时,该立即存储到SavedGrade列中。(我们SavedGrade直接更新,否则约束不允许我们设置Finalised'true'。)一旦Finalised设置,由于约束,您不能再更改Grade列。

于 2011-07-07T21:08:20.043 回答
-3

IMO,我想说它应该在应用程序或存储过程(可能两者)中完成,而不是作为实际约束(除其他外,在您的具体示例中,“最终确定”的成绩并不总是意味着它实际上是最终的)。

但是,如果我将其作为约束来实现,我会使用 CHECK 约束(再次使用您的示例)

CONSTRAINT chk_grade CHECK(grade between 0 AND 100 and finalized = 0)

检查具体的语法,但这是我要开始的地方。

于 2011-07-07T20:14:11.540 回答