使用触发器进行约束的SQL

使用触发器进行约束的SQL,sql,triggers,constraints,Sql,Triggers,Constraints,我正在研究触发器和约束 我有一个关于使用触发器的问题(说实话,我真的不知道如何使用触发器…) 假设我们有一张教师桌 这个教师表包含教师id、ssn、名字、姓氏、班级时间 比如说, |teacher_id|ssn | first_name | last_name | student_number| max_student |1 |1234 | bob | Smith | 25 |25 |2 |1235 | k

我正在研究触发器和约束

我有一个关于使用触发器的问题(说实话,我真的不知道如何使用触发器…)

假设我们有一张教师桌

这个教师表包含教师id、ssn、名字、姓氏、班级时间

比如说,

|teacher_id|ssn    | first_name | last_name | student_number| max_student
|1         |1234   | bob        | Smith     | 25            |25
|2         |1235   | kim        | Johnson   | 24            |21
|3         |1236   | kally      | Jones     | 23            |22

假设学生人数的最大值为25。(学生人数的最大值由老师定义,因此可以是任何数字,如10、22、25…)

一个学生想加入鲍勃的班级。但是,我想触发拒绝添加学生的触发。(因为bob的课已经满了。)

但是,我不确定如何创建触发器..:(…(这是第一次研究触发器…)


有人可以帮助创建示例代码来理解触发器部分吗?

首先,我认为这是一个数据规则,因此应该集中实施。也就是说,DBMS应该实施一个数据库约束(或等效约束),以防止所有应用程序写入错误数据(而不是依赖于每个应用程序的单个编码器来避免写入坏数据)

第二,我认为在之后使用
触发器是合适的(而不是使用
而不是
触发器)

第三,可以使用外键和行级别
CHECK
约束强制执行此操作

对于约束类型触发器,通常的想法是编写一个查询以返回错误数据,然后在触发器测试中确认该结果为空

您没有发布很多表的详细信息,所以我猜。我假设
学生编号
是学生的计数;因为它听起来像一个标识符,所以我将更改名称,并假设学生的标识符是
学生id

WITH EnrolmentTallies
     AS
     (
      SELECT teacher_id, COUNT(*) AS students_tally
        FROM Enrolment
       GROUP 
          BY teacher_id      
     ) 
SELECT * 
  FROM Teachers AS T
       INNER JOIN EnrolmentTallies AS E
         ON T.teacher_id = E.teacher_id
            AND E.students_tally > T.students_tally;
在SQL Server中,触发器定义如下所示:

CREATE TRIGGER student_tally_too_high ON Enrolment
AFTER INSERT, UPDATE
AS
IF EXISTS (
           SELECT * 
             FROM Teachers AS T
                  INNER JOIN (
                              SELECT teacher_id, COUNT(*) AS students_tally
                                FROM Enrolment
                               GROUP 
                                  BY teacher_id      
                             ) AS E
                                  ON T.teacher_id = E.teacher_id
                                     AND E.students_tally > T.students_tally
          )
BEGIN
RAISERROR ('A teachers''s student tally is too high to accept new students.', 16, 1);
ROLLBACK TRANSACTION;
RETURN 
END;
但是,还有一些进一步的考虑。在每次
更新表之后执行这样的查询可能效率很低。如果您认为可以依赖列顺序,则应使用
UPDATE()
(或
COLUMNS\u UPDATED
)和/或
deleted
inserted
概念表,以限制查询的范围和触发查询的时间。您还需要确保事务已正确序列化,以防止并发问题。虽然涉及到事务,但并不十分复杂

我强烈推荐这本书,第11章(代码示例是Oracle,但可以很容易地移植到SQL Server)


在没有触发器的情况下也可以实现同样的效果。其想法是在
(教师id,学生计数)
上制作一个超级键,以供注册时参考,对于该超级键,将保留一个唯一学生出现的序列,并进行一项测试,确保该序列永远不会超过最大计数

以下是一些基本的SQL DDL:

CREATE TABLE Students 
(
 student_id INTEGER NOT NULL,
 UNIQUE (student_id)
);

CREATE TABLE Teachers 
(
 teacher_id INTEGER NOT NULL,
 students_tally INTEGER NOT NULL CHECK (students_tally > 0), 
 UNIQUE (teacher_id), 
 UNIQUE (teacher_id, students_tally)
);

CREATE TABLE Enrolment
(
 teacher_id INTEGER NOT NULL UNIQUE,
 students_tally INTEGER NOT NULL CHECK (students_tally > 0), 
 FOREIGN KEY (teacher_id, students_tally)
    REFERENCES Teachers (teacher_id, students_tally)
    ON DELETE CASCADE
    ON UPDATE CASCADE, 
 student_id INTEGER NOT NULL UNIQUE 
    REFERENCES Students (student_id),
 student_teacher_sequence INTEGER NOT NULL
    CHECK (student_teacher_sequence BETWEEN 1 AND students_tally)
 UNIQUE (teacher_id, student_id), 
 UNIQUE (teacher_id, student_id, student_teacher_sequence)
);

然后添加一些“帮助”存储的过程/函数,以在更新时维护序列。

您必须添加您感兴趣的数据库,因为触发器往往是特定于数据库的。这是一个业务规则,我希望在您的应用程序软件中实现,而不是作为数据库中的触发器或约束。Databasese约束和触发器通常强制引用完整性(即,它们在内部保持数据一致)而且,尽管这可能是确保类数不超过25的一个后盾,但您的应用程序首先应该真正停止尝试。@Andreweach:我同意在使用数据库的每个应用程序中都应该强制执行该规则。我不同意这是一个非此即彼的考虑因素。理想情况是数据库和应用程序都使用common business rules repository;如果不可能,则应在这两个位置强制执行,即应用程序应避免通过验证写入坏数据,数据库应防止通过约束提交坏数据。p.s.Excel是处理数据库的常用应用程序(给他们特权,他们会来的!):如何在Excel中执行规则?!@AndrewLeach:据我所知,
25
是Bob班级可以注册的最大学生人数。当第26名学生注册Bob班级时,数据不一致,因为
teachers
表中说班级规模不能超过
25
@AndrewLeach:在我看来,您对“不一致”的定义似乎与词典中的含义不同,也不直观。我想知道您是否可以提供引用?请记住,数据库表中的一行是一个谓词,它被认为是真的。一个表中的一行表示不超过25名学生可以上Bob的课。另一个表中的一行表示不超过25名学生可以上Bob的课可能会说拉维是鲍勃班上第26个被录取的学生。这两个都不可能是真的。这怎么不“不一致”呢?对不起,我忘了把max_student放在表中。我正在研究创建一个触发器,当学生想要注册课程时,它可以检查注册限制。例如,如果max_student==student_number,那么学生就不能添加c姑娘。不管怎样,它真的帮助我理解触发器。谢谢:)