我正在研究触发器和约束。
我有一个关于使用触发器的问题(老实说,我不太确定如何使用触发器。)
假设我们有一张教师桌。
该教师表包含teacher_id、ssn、first_name、last_name、class_time
例如,
|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的课已经满了。)
但是,我真的不确定创建触发器的方法。:( ..(这是第一次研究触发器……)
有人可以帮助创建示例代码来理解触发器部分吗?
发布于 2012-03-12 16:39:20
首先,我认为这是一个数据规则,因此应该集中执行。也就是说,应该有一个由DBMS强制执行的数据库约束(或等效约束),以防止所有应用程序写入坏数据(而不是依赖每个应用程序的各个编码器来避免写入坏数据)。
其次,我认为AFTER触发器是合适的(而不是INSTEAD OF触发器)。
第三,这可以使用外键和行级CHECK约束来强制执行。
对于约束类型触发器,通常的想法是编写一个查询来返回错误数据,然后在触发器测试中确定此结果为空。
您还没有发布您的表的许多详细信息,所以我将猜测。我假设student_number是用来统计学生人数的;因为它听起来像是一个标识符,所以我将更改名称,并假定学生的标识符是student_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之后执行这样的查询可能效率非常低。您应该使用UPDATE() (如果您认为可以依赖列排序,则使用COLUMNS_UPDATED )和/或deleted和inserted概念表来限制查询的范围和触发查询的时间。您还需要确保事务被正确序列化,以防止并发问题。虽然很复杂,但并不是很复杂。
我强烈推荐Applied Mathematics for Database Professionals By Lex de Haan, Toon Koppelaars这本书,第11章(代码示例是Oracle,但可以很容易地移植到SQL Server)。
在没有触发器的情况下,也有可能实现同样的效果。这个想法是在(teacher_id, students_tally)上创建一个超键,以在注册中引用,对于该超键,将通过测试来维护唯一学生出现的序列,该序列永远不会超过最大计数。
下面是一些简单的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)
);然后添加一些“help”存储的procs/函数,以维护更新时的顺序。
https://stackoverflow.com/questions/9663263
复制相似问题