通辽市做网站公司版权申请网站

news/2025/10/4 3:07:16/文章来源:
通辽市做网站公司,版权申请网站,彩票网站 建设,找个免费的网站目录 1.触发器1.1.DDL触发器1.2.DML触发器1.3.创建触发器1.3.1.创建DML触发器1.3.2.创建DDL触发器1.3.3.嵌套触发器1.3.4.递归触发器1.4.管理触发器1.触发器 触发器是一种特殊的存储过程#xff0c;与表紧密关联。 1.1.DDL触发器 当服务器或数据库中发生数据定义语言#xff… 目录 1.触发器1.1.DDL触发器1.2.DML触发器1.3.创建触发器1.3.1.创建DML触发器1.3.2.创建DDL触发器1.3.3.嵌套触发器1.3.4.递归触发器1.4.管理触发器 1.触发器 触发器是一种特殊的存储过程与表紧密关联。 1.1.DDL触发器 当服务器或数据库中发生数据定义语言DDL事件时将被调用。如CREATE,ALTERDROP等操作。如果要执行以下操作可以使用DDL触发器 防止对数据库架构进行更改希望数据库中发生某些情况以响应数据库架构中的更改要记录数据库架构中的更改或事件1.2.DML触发器 当数据库服务器中发生数据操作语言DML事件时将被调用。如INSERT,DELETE,UPDATE等操作。将DML触发器和触发语句作为可在触发器内回滚的单个事务对待如果检测到错误则整个事务回滚。DML触发器在一下方面非常有用 可实现数据库相关表之间的级联更改可以防止恶意或错误的DML语句事件并强制执行比CHECK约束更为复杂的其他限制可以评估数据修改前后表的状态并根据该差异采取措施一个表中的多个同类DML触发器允许用多个不同的操作来响应同一个修改语句SQL Server 2008为每个触发器创建了2个特殊的表INSERTED表和DELETED表。这是两个逻辑表由系统来创建和维护用户不能对他们进行修改。它们存放在内存中而不是在数据库中并且结构与被DML触发器作用的表的结构相同。INSERTED表中存放了由执行INSERT或UPDATE语句而插入的所有行在执行INSERT或UPDATE语句时新的行将同时被插入到触发器作用的表和INSERTED表中。INSERTED表中的行是触发器作用的表中行的副本。DELETED表中存放了由执行DELETE或UPDATE语句而删除的所有行在执行DELETE或UPDATE语句时被删除的行将由触发器作用的表中被移动到DELETED表两个表中不会有重复行。 1.3.创建触发器 1.3.1.创建DML触发器 1.3.1.1.INSERT触发器 示例1创建一个触发器Automatic_division当在Student表中插入一条学生信息时触发器根据入学分数stu_enter_score对学生进行自动分班并在class_student表中插入一条记录。 分班要求 |Stu_enter_score |Class_id |Class_name| |-------------------|------------------|--------------| |stu_enter_score700| 01| 创新A班| |650Stu_enter_score700| 02| 重点B班| |600Stu_enter_score650| 03| 提高C班| |550Stu_enter_score600| 04| 普通D班| |500Stu_enter_score550| 05| 普通E班| |Stu_enter_score500| 06| 普通F班| 执行下列语句 CREATE TRIGGER automatic_division ON student--新建一个检测student表的触发器,命名automatic_division FOR INSERT--检测到INSERT操作时触发器工作 AS DECLARE score INT,stu_no VARCHAR(8),class_id CHAR(2) --声明三个变量 DECLARE stu_cursor CURSOR LOCAL FORWARD_ONLY--声明一个指向inserted表的局部游标stu_cursor FOR SELECT stu_no,stu_enter_score FROM inserted OPEN stu_cursor--打开游标 FETCH NEXT FROM stu_cursor INTO stu_no,score--将游标指向inserted表的第一个数据并把游标指向的stu_no和stu_enter_score值分别赋值给stu_no和score WHILE FETCH_STATUS0--开始循环 BEGIN BEGIN--先对score的数值范围做判断以确定该学生的班级编号 IF score700 SET class_id01 ELSE IF score700 AND score650 SET class_id02 ELSE IF score650 AND score600 SET class_id03 ELSE IF score600 AND score550 SET class_id04 ELSE IF score550 AND score500 SET class_id05 ELSE SET class_id06 END --判断结束 INSERT INTO class_student(class_id,stu_no) VALUES(class_id,stu_no)--将数据插入到class_student表中 FETCH NEXT FROM stu_cursor INTO stu_no,score--将游标移向inserted表的下一个数据重复这个循环 END--循环结束 CLOSE stu_cursor--关闭游标 DEALLOCATE stu_cursor--释放游标资源 GO 验证代码是否正确 向student表中插入数据并查看class_student表中的数据是否正确 INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score) VALUES(20180001,邹莉莉,女,389), (20180002,万兴,男,701), (20180003,孙伟,男,652), (20180004,温佳静,女,676), (20180005,姜立夫,男,542) Class_student表中的数据如图所示游标示例2对student表中还未分班的学生进行分班Student表中的数据如图所示 其中stu_no为20180001~20180005的学生已经在示例1中分班剩下的学生全都未分班。 执行下列语句 ALTER TABLE student ADD stu_division_state bit--为student表新建一列记录是否已分班true表示已分班 GO DECLARE stu_class_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no FROM class_student --新建游标stu_class_cursor指向class_student表的所有数据 OPEN stu_class_cursor--打开游标 DECLARE stu_no VARCHAR(8) FETCH NEXT FROM stu_class_cursor INTO stu_no WHILE FETCH_STATUS0 BEGIN UPDATE student SET stu_division_state1 WHERE stu_nostu_no FETCH NEXT FROM stu_class_cursor INTO stu_no END CLOSE stu_class_cursor--关闭游标 DEALLOCATE stu_class_cursor--释放游标资源 ---所有学生是否分班已经全部记录在stu_division_state中 GO DECLARE stu_no VARCHAR(8),score INT,class_id CHAR(2) DECLARE stu_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no,stu_enter_score FROM student WHERE stu_division_state IS NULL --新建student表的游标stu_cursor指向所有未分班学生 OPEN stu_cursor--打开游标 FETCH NEXT FROM stu_cursor INTO stu_no,score WHILE FETCH_STATUS0--循环开始 BEGIN BEGIN--先对score的数值范围做判断以确定该学生的班级编号 IF score700 SET class_id01 ELSE IF score700 AND score650 SET class_id02 ELSE IF score650 AND score600 SET class_id03 ELSE IF score600 AND score550 SET class_id04 ELSE IF score550 AND score500 SET class_id05 ELSE SET class_id06 END INSERT INTO class_student(class_id,stu_no) VALUES(class_id,stu_no)--将数据插入到class_student表中 UPDATE student--将student表的stu_division_state改成已分班 SET stu_division_state1 WHERE stu_nostu_no FETCH NEXT FROM stu_cursor INTO stu_no,score--将游标移向inserted表的下一个数据重复这个循环 END--循环结束 CLOSE stu_cursor DEALLOCATE stu_cursor GO 结果如图所示Student表的数据Class_student表的数据 至此Student表中所有学生都已分班 为了以后方便可以将游标示例2中的代码稍作修改封装成一个用户自定义存储过程存储过程示例3 修改后的代码如下 CREATE PROCEDURE student_division AS BEGIN UPDATE student SET stu_division_state0--先将student表中所有学生的分班情况都标成未分班DECLARE stu_class_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no FROM class_student --新建游标stu_class_cursor指向class_student表的所有数据 OPEN stu_class_cursor--打开游标 DECLARE stu_no VARCHAR(8) FETCH NEXT FROM stu_class_cursor INTO stu_no WHILE FETCH_STATUS0 BEGIN UPDATE student SET stu_division_state1 WHERE stu_nostu_no--利用游标找出student表中已分班的学生并标记分班状态 FETCH NEXT FROM stu_class_cursor INTO stu_no END CLOSE stu_class_cursor--关闭游标 DEALLOCATE stu_class_cursor--释放游标资源 ---所有学生是否分班已经全部记录在stu_division_state中DECLARE score INT,class_id CHAR(2) DECLARE stu_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no,stu_enter_score FROM student WHERE stu_division_state0 --新建student表的游标stu_cursor指向所有未分班学生 OPEN stu_cursor--打开游标 FETCH NEXT FROM stu_cursor INTO stu_no,score WHILE FETCH_STATUS0--循环开始 BEGIN BEGIN--先对score的数值范围做判断以确定该学生的班级编号 IF score700 SET class_id01 ELSE IF score700 AND score650 SET class_id02 ELSE IF score650 AND score600 SET class_id03 ELSE IF score600 AND score550 SET class_id04 ELSE IF score550 AND score500 SET class_id05 ELSE SET class_id06 END INSERT INTO class_student(class_id,stu_no) VALUES(class_id,stu_no)--将数据插入到class_student表中 UPDATE student--将student表的stu_division_state改成已分班 SET stu_division_state1 WHERE stu_nostu_no FETCH NEXT FROM stu_cursor INTO stu_no,score--将游标移向inserted表的下一个数据重复这个循环 END--循环结束 CLOSE stu_cursor DEALLOCATE stu_cursor END GO 注和游标示例2的代码相比示例3的代码添加了将所有学生分班状态标记为0的过程去掉了添加stu_division_state列的过程但对原来已有的学生的分班状态赋值这个步骤并未删去而是进行重复校验。并且删除了两段代码中的GO和第二段用于给学生分班的代码中对stu_no变量的重复声明。 对student表插入数据并运行student_division的存储过程 注对student表插入数据前应先禁用示例1的触发器automatic_division 执行下列语句 ALTER TABLE student DISABLE TRIGGER automatic_division --禁用automatic_division触发器 INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score,stu_division_state) VALUES(20180006,王洋,男,724,NULL), (20180007,易阳,男,713,NULL), (20180008,孙浩,男,584,NULL), (20180009,张秋燕,女,420,False), (20180010,胡燕,女,527,True) Student表的数据如图所示红框内就是我刚刚插入还未分班的数据其中20180009和20180010这两个学生的分班状态被我误标成False和True 执行存储过程 EXEC dbo.student_division 结果如图所示Student表的数据分班状态都为true了Class_student表的数据 1.3.1.2.DELETE触发器 当针对目标数据库运行DELETE语句时就会激活DELETE触发器。用户直接运行DELETE语句和使用DELETE触发器又有所不同当激活DELETE触发器后从受触发器影响的表中删除的行会被放置在一个特殊的临时表——DELETED表中。DELETED表还允许引用由初始化DELETE语句产生的日志数据。 当DELETE触发器被激活时需要考虑以下几点 当某行被添加到DELETED表中时就不存在于数据库表因此数据库表和DELETED表不可能存在相同行。系统自动创建DELETED表时空间从内存中分配。DELETED表被存储在高速缓存中。为DELETE操作定义的触发器并不执行TRUNCATE TABLE语句原因在于日志不记录TRUNCATE TABLE语句。示例4为student表定义一个DELETE触发器当删除一条学生信息时class_student表中该学生的分班信息也会被删除 执行下面的语句 CREATE TRIGGER delete_student ON student FOR DELETE AS DECLARE stu_no VARCHAR(8) DECLARE stu_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no FROM deleted OPEN stu_cursor FETCH NEXT FROM stu_cursor INTO stu_no WHILE FETCH_STATUS0 BEGIN DELETE FROM class_student WHERE stu_nostu_no FETCH NEXT FROM stu_cursor INTO stu_no END CLOSE stu_cursor DEALLOCATE stu_cursor GO 测试delete_student触发器的正确性Student表的数据如图所示Class_student表的数据如图所示 执行下列语句 DELETE FROM student WHERE stu_enter_score351 --在student表中删除入学成绩小于分的学生 从student表来看只有入学编号为20180011和20180012的学生成绩被删除。该操作激活了delete_student触发器Class_student表的数据如图所示 入学编号为20180011和20180012的学生分班信息已经从class_student表中自动删除。 1.3.1.3.UPDATE触发器 当针对目标数据库运行UPDATE语句时就会激活UPDATE触发器。对UPDATE触发器来说临时表INSERTED和DELETED依然有用。UPDATE触发器被激活时原始行被移入DELETED表中更新行被移入到INSERTED表中。触发器检查DELETED表和INSERTED表以及被更新的表来确定是否更新了多行和如何执行触发器动作。Student表的数据如图所示Class_student表的数据如图所示示例5当student表中的stu_no字段更新时同步更新class_student表中的stu_no字段 执行下列语句新建触发器update_stu_no_single CREATE TRIGGER update_stu_no_single ON student FOR UPDATE AS IF UPDATE(stu_no) BEGIN UPDATE class_student SET stu_no(SELECT stu_no FROM inserted) WHERE stu_no(SELECT stu_no FROM deleted) END GO 验证update_stu_no_single触发器是否正确在Student表中执行下列语句将student表中stu_no为“20180101”的学生的stu_no改成00000000 UPDATE student SET stu_no00000000 WHERE stu_no20180101 执行成功后update_stu_no_single触发器被激活class_student表的数据如图所示 注update_stu_no_single触发器只能对单行记录的UPDATE操作起效如果批量UPDATE stu_no执行语句时会提示子查询返回的值不止1个。下面的示例6将提供批量UPDATE stu_no的触发器 示例6实现当student表的stu_no字段批量更新时class_student表的stu_no也同步批量更新 首先将student表和class_student表的数据修改成原来的样子并且删除update_stu_no_single触发器Student表的数据如图所示Class_student表的数据如图所示 执行下列语句新建触发器update_stu_no_batch CREATE TRIGGER update_stu_no_batch ON student FOR UPDATE AS DECLARE stu_no_insert VARCHAR(8),stu_no_delete VARCHAR(8) DECLARE stu_cursor_insert CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no FROM inserted OPEN stu_cursor_insert DECLARE stu_cursor_delete CURSOR LOCAL FORWARD_ONLY FOR SELECT stu_no FROM deleted OPEN stu_cursor_delete FETCH NEXT FROM stu_cursor_insert INTO stu_no_insert FETCH NEXT FROM stu_cursor_delete INTO stu_no_delete WHILE FETCH_STATUS0 BEGIN UPDATE class_student SET stu_nostu_no_insert WHERE stu_nostu_no_delete FETCH NEXT FROM stu_cursor_insert INTO stu_no_insert FETCH NEXT FROM stu_cursor_delete INTO stu_no_delete END CLOSE stu_cursor_insert CLOSE stu_cursor_delete DEALLOCATE stu_cursor_insert DEALLOCATE stu_cursor_delete GO 验证update_stu_no_batch触发器的准确性对student表执行下列语句实现批量修改操作 UPDATE student SET stu_no00000000 WHERE stu_no LIKE 201801% GO Student表的数据如图所示Class_student表的数据如图所示 我们再来验证update_stu_no_batch触发器对更新单行stu_no数据是否有效。将student表和class_student表的数据改回原来的样子然后执行下列语句 UPDATE student SET stu_no00000000 WHERE stu_no20180101 Class_student表的数据如图所示 注在将表数据改成原来的样子时直接在编辑前200行中操作或者用T-SQL语句操作对student表数据操作不成功的话要考虑受键和约束的影响对class_student表数据操作不成功的话要考虑受触发器影响。 1.3.1.4.INSTEAD OF触发器 用INSTEAD OF触发器可以指定执行触发器而不是执行触发SQL语句从而屏蔽原来的SQL语句而转向执行触发器内部的语句。每个表或者视图只能有1个INSTEAD OF触发器。INSTEAD OF触发器的特点是能够使作为触发条件的SQL语句不执行。Membership表的数据如图所示Call_slip表的数据如图所示示例7对LibraryManagement数据库里的membership表写一个防删除触发器尚有借书未还的读者无法被删除 执行下列语句创建member_delete_single触发器 CREATE TRIGGER member_delete_single ON membership INSTEAD OF DELETE AS BEGIN IF NOT EXISTS(SELECT * FROM call_slip WHERE member_id(SELECT member_id FROM deleted) AND borrow_state未归还) DELETE FROM membership WHERE member_id(SELECT member_id FROM deleted) ELSE BEGIN SELECT 该用户尚有图书未还无法删除 SELECT * FROM call_slip WHERE member_id(SELECT member_id FROM deleted) AND borrow_state未归还 END END GO 验证触发器的正确性执行下列语句 DELETE FROM membership WHERE member_id20060128 结果如图所示 该触发器只针对DELETE一条数据有效示例8对LibraryManagement数据库里的membership表写一个防批量删除触发器尚有借书未还的读者无法被删除Membership表的数据如图所示Call_slip表的数据如图所示 执行下列语句新建触发器将示例7中的member_delete_single触发器先删除 CREATE TRIGGER member_delete_batch ON membership INSTEAD OF DELETE AS BEGIN DECLARE member_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT member_id FROM deleted OPEN member_cursor DECLARE member_id VARCHAR(8) FETCH NEXT FROM member_cursor INTO member_id WHILE FETCH_STATUS0 BEGIN BEGIN IF NOT EXISTS(SELECT* FROM call_slip WHERE member_idmember_id AND borrow_state未归还) DELETE FROM membership WHERE member_idmember_id ELSE PRINT 用户member_id无法删除 END FETCH NEXT FROM member_cursor INTO member_id END CLOSE member_cursor DEALLOCATE member_cursor END GO 结果如图所示Membership表的数据如图所示示例9对LibraryManagement数据库里的call_slip表写一个防超借触发器一个读者的未还图书最多只能有5本超出不能再借这里还是针对批量处理数据创建触发器Call_slip表的数据如图所示 执行下列语句创建provent_overborrowing_batch触发器 CREATE TRIGGER provent_overborrowing_batch ON call_slip INSTEAD OF INSERT AS BEGIN DECLARE member_id VARCHAR(8) DECLARE borrow_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT DISTINCT member_id FROM inserted OPEN borrow_cursor FETCH NEXT FROM borrow_cursor INTO member_id WHILE FETCH_STATUS0 BEGIN BEGIN IF (SELECT COUNT(*) FROM call_slip WHERE member_idmember_id AND borrow_state未归还)5 INSERT INTO call_slip SELECT * FROM inserted WHERE member_idmember_id ELSE PRINT 用户member_id已借阅且未还的图书超过5本无法再借 END FETCH NEXT FROM borrow_cursor INTO member_id END END GO 执行下列语句测试provent_overborrowing_batch触发器的正确性其中member_id为“20060128”的用户借书未还超过5本应该是无法再借的。 --测试数据 INSERT INTO call_slip(book_id,member_id,loan_period,borrow_state) VALUES(20130002,20060128,30,未归还), (20130001,20060128,20,未归还), (20130003,20060128,30,未归还), (20130004,20062919,30,未归还), (20130005,20150821,45,未归还) 结果如图所示Call_slip表的数据如图所示红框里是新插入的数据 1.3.2.创建DDL触发器 DDL触发器只为了响应CREATEDROPALTER事件而激活它的作用域是整个数据库或者服务器而不是作用域某张表或试图。它可以有效控制哪位用户可以修改数据库结构以及如何修改。示例10创建一个DDL触发器控制上班时间8:00-18:00不能对LibraryManagement数据库表和试图结构进行新建修改和删除操作。 执行下列语句创建触发器deny_DDL_table CREATE TRIGGER deny_DDL_table ON DATABASE WITH ENCRYPTION FOR CREATE_TABLE,DROP_TABLE,ALTER_TABLE AS DECLARE eventdata XML SET eventdataEVENTDATA() IF(DATEPART(HOUR,GETDATE()) BETWEEN 8 AND 17) BEGIN SELECT 触发器deny_DDL_table已禁止工作时间8:00-18:00对LibraryManagement数据库的CREATE,ALTER,DROP操作 SELECT eventdata.value((/EVENT_INSTANCE/EventType)[1],nvarchar(max)) AS EventType,--事件类型 eventdata.value((/EVENT_INSTANCE/PostTime)[1],nvarchar(max)) AS PostTime,--时间触发的时间 eventdata.value((/EVENT_INSTANCE/DatabaseName)[1],nvarchar(max)) AS DatabaseName,--数据库名字 eventdata.value((/EVENT_INSTANCE/ObjectName)[1],nvarchar(max)) AS ObjectName,--操作的对象名称 eventdata.value((/EVENT_INSTANCE/ObjectType)[1],nvarchar(max)) AS ObjectType,--操作的对象类型 eventdata.value((/EVENT_INSTANCE/TSQLCommand/CommandText)[1],nvarchar(max)) AS CommandText--操作命令文本 ROLLBACK---对操作进行回滚也可以不回滚 END GO 执行以下代码以测试DDL触发器deny_DDL_table的正确性 USE LibraryManagement CREATE TABLE test( t_id VARCHAR(2), t_name VARCHAR(20) ) 结果如图所示 注EVENTDATA()可在触发器内部使用返回有关数据库和服务器事件的信息以XML格式返回。只有直接在DDL或登录触发器内部引用EVENTDATA时EVENTDATA才会返回数据。如果EVENTDATA由其他例程调用即使这些例程由DDL或登录触发器进行调用将返回 NULL。 1.3.3.嵌套触发器 1.3.3.1.嵌套触发器 如果一个触发器在执行操作时引发了另一个触发器而这个触发器又引发了下一个触发器那么这些触发器就是嵌套触发器。嵌套触发器在安装时就被启用但是可以使用sp_configure存储过程禁用和重新启用嵌套。DML触发器和DDL触发器最多可以嵌套32层可以通过nested triggers来配置是否可以嵌套AFTER触发器但是不管此设置如何都可以嵌套INSTEAD OF触发器。如果嵌套触发器进入了无限循环该触发器将被终止并且回滚整个事务。嵌套触发器具有多种用途比如保存前一个触发器所影响的行的副本。 使用嵌套触发器时应该注意以下几点 默认情况下嵌套触发器配置选项开启。在同一个触发器事务中一个触发器不会被触发两次触发器不会调用他自己来响应触发器中对同一个表的第二次更新由于触发器是一个事务一旦嵌套中任何一层的触发器出现错误将回滚整个事务。示例11有teacher_course表教师所教课程表course表课程表和course_selection表学生选课表写一个嵌套触发器实现课程取消后删除教师所教课程表中关于该课程的记录而教师所教课程表中该课程的记录被取消导致该课程的学生选课记录也做相应取消。 执行下列语句 --创建course表上的触发器删除course表中的课程teacher_course表中的记录做对应删除 CREATE TRIGGER course_delete_batch ON course FOR DELETE AS DECLARE course_id CHAR(4) DECLARE course_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT course_id FROM deleted OPEN course_cursor FETCH NEXT FROM course_cursor INTO course_id WHILE FETCH_STATUS0 BEGIN DELETE FROM teacher_course WHERE course_idcourse_id FETCH NEXT FROM course_cursor INTO course_id END GO --创建teacher_course表上的触发器删除教师课程表的记录学生选课表的记录也做对应删除 CREATE TRIGGER teacher_course_delete_batch ON teacher_course FOR DELETE AS DECLARE course_id CHAR(4) DECLARE teacher_course_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT DISTINCT course_id FROM deleted OPEN teacher_course_cursor FETCH NEXT FROM teacher_course_cursor INTO course_id WHILE FETCH_STATUS0 BEGIN IF (SELECT COUNT(*) FROM teacher_course WHERE course_idcourse_id)0 DELETE FROM course_selection WHERE course_idcourse_id ELSE PRINT course_id为course_id的课程依然正常开课该课程的学生选课情况不予删除 FETCH NEXT FROM teacher_course_cursor INTO course_id END GO course_delete_batch和** teacher_course_delete_batch就形成了一个嵌套触发器下面来验证嵌套触发器的正确性。Course表中的数据如图所示Teacher_course表中的数据如图所示Course_selection**表中的数据如图所示 以课程0013为例执行下列语句 DELETE FROM course WHERE course_id0013 Course表的数据如图所示Teacher_course表的数据如图所示Course_selection表的数据如图所示 所有关于0013课程的数据都被删除。嵌套触发器有效。 注在触发器teacher_course_delete_batch中我额外加入了一个判断当teacher_course表中还有老师在教授这门课程时所有关于这门课程的学生选课信息都不予删除。这样做在嵌套触发器里是多余的删除一门课程必然会删除teacher_course表中所有与这门课程有关的记录也必然删除course_selection表中所有与这门课程有关的记录但是这样做可以保证该触发器能够独立于嵌套触发器被单独激活。Teacher_course_delete_batch触发器还能用于其他嵌套触发器中看示例12。 示例12有teacher表教师信息表,teacher_course教师所教课程表和course_selection表学生选课记录表,写一个嵌套触发器实现当一个教师离职时在删除该教师所教课程信息如果没有教师教这门课程再删除该课程选课记录。 其中teacher_course表的触发器teacher_course_delete_batch已经在示例11中写完只需创建teacher表的teacher_delete_batch触发器即可 执行下列代码 CREATE TRIGGER teacher_delete_batch ON teacher FOR DELETE AS DECLARE teacher_id CHAR(4) DECLARE teacher_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT teacher_id FROM deleted OPEN teacher_cursor FETCH NEXT FROM teacher_cursor INTO teacher_id WHILE FETCH_STATUS0 BEGIN DELETE FROM teacher_course WHERE teacher_idteacher_id FETCH NEXT FROM teacher_cursor INTO teacher_id END GO 测试嵌套触发器的正确性Teacher表的数据如图所示Teacher_course表的数据如图所示Course_selection表的数据如图所示 以删除0012号教师路易为例0012号教师教授0013号课程且teacher_course表中并无其他教师教授0013号课程按照逻辑要删除teacher_course表中0012号教师的所教课程记录和course_selection表中所有0013号课程的选课记录。执行下列语句 DELETE FROM teacher WHERE teacher_id0012 Teacher表的数据如图所示Teacher_course表的数据如图所示Course_selection表的数据如图所示 测试结果正确 参照上面的数据继续测试另一种情况以删除0011号教师卢含笑为例0011号教师教授0012号课程在teacher_course表中还有其他教师教授该课程因此嵌套触发器会删除teacher_course表中关于0011号教师教授课程记录但不会删除course_selection表中关于0012号课程的选课记录。执行下列语句 DELETE FROM teacher WHERE teacher_id0011 GO 结果如图所示Teacher表的数据如图所示Teacher_course表的数据如图所示Course_selection表的数据如图所示 1.3.3.2.查看触发器嵌套的层数 可以使用NESTLEVEL全局变量来查看当前触发器嵌套的层数示例13在示例11的teacher_course_delete_batch触发器中利用NESTLEVEL全局变量查看当前触发器嵌套的层数 执行下列语句修改teacher_course_delete_batch触发器 ALTER TRIGGER teacher_course_delete_batch ON teacher_course FOR DELETE AS DECLARE course_id CHAR(4) DECLARE teacher_course_cursor CURSOR LOCAL FORWARD_ONLY FOR SELECT DISTINCT course_id FROM deleted OPEN teacher_course_cursor FETCH NEXT FROM teacher_course_cursor INTO course_id WHILE FETCH_STATUS0 BEGIN IF (SELECT COUNT(*) FROM teacher_course WHERE course_idcourse_id)0 DELETE FROM course_selection WHERE course_idcourse_id ELSE PRINT course_id为course_id的课程依然正常开课该课程的学生选课情况不予删除 FETCH NEXT FROM teacher_course_cursor INTO course_id SELECT NESTLEVEL AS NESTLEVEL END GO 测试teacher_course_delete_batch触发器数据就不看了未影响触发器原来的功能 执行下列语句 DELETE FROM teacher_course WHERE teacher_id0009 --直接在teacher_course表中删除激活teacher_course_delete_batch触发器 结果如图所示 执行下列语句 DELETE FROM teacher WHERE teacher_id0009 --在teacher表中删除触发teacher_delete_batch触发器进而触发teacher_course_delete_batch触发器 结果如图所示 1.3.3.3.禁用和启用嵌套触发器 EXEC sp_configure nested triggers,0; GO --禁用嵌套触发器 EXEC sp_configure nested triggers,1; GO --启用嵌套触发器 1.3.4.递归触发器 1.3.4.1.递归触发器 触发器被激活更改了表中数据这种更改又激活了它自己这种触发器被称为递归触发器。数据库创建时默认递归触发器禁用。但可以使用ALTER DATABASE选项来启用它。递归触发器启用的先决条件是嵌套触发器必须是启用状态如果嵌套触发器禁用不管递归触发器的配置是什么都将被禁用。而在递归触发器中inserted表和deleted表都只包含被上一次触发器影响的行数据。 递归触发器有以下两种不同类型这边没有合适的应用示例可举先不举例了 1.3.4.2.直接递归 直接递归触发器是指整个递归过程只有它本身一个触发器的参与。自己激活了自己。 1.3.4.3.间接递归 间接递归触发器是指整个递归过程有多个触发器参与例如A激活BB激活CC激活A。可以看成是递归和嵌套的结合。 使用递归触发器时需要注意以下几点 递归触发器很复杂需要经过有条理的设计和全面测试 在任意点的数据修改都会激活递归触发器。只能按触发器被激活的特定顺序更新表。 所有触发器一起构成一个大事务任意触发器的任意位置上的ROLLBACK语句都将取消所有数据的输入所有数据均被擦除。 触发器最多只能递归16层一旦有第17个触发器参与进来结果与ROLLBACK命令一样所有数据都将被擦除 1.3.4.4.启用递归触发器 可以使用SQL Server 2008的管理器工具来启用递归触发器。 1.4.管理触发器 禁用和启用触发器 执行下列语句禁用和启用触发器 ALTER TABLE student DISABLE TRIGGER update_stu_no_single --禁用update_stu_no_single触发器 GO ALTER TABLE student ENABLE TRIGGER update_stu_no_single --启用update_stu_no_single触发器 GO 执行下列语句禁用和启用数据库级别触发器 DISABLE TRIGGER deny_DDL_table ON DATABASE --禁用数据库级别触发器deny_DDL_table GO ENABLE TRIGGER deny_DDL_table ON DATABASE --启用数据库级别触发器deny_DDL_table GO转载于:https://www.cnblogs.com/kukubear0/p/9337116.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/926546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设推广熊掌号鞋网站建设

🎶Leetcode 151. 反转字符串中的单词 难度:中等 ✨题目描述: 给你一个字符串 s ,请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 …

电脑做服务器建网站并让外网访问成都网页设计培训哪家好

在这里和下一级别的分析中有必要先讲一下这个h->mb.cache(没法讲,就是cache!)。 x264_macroblock_cache_load将参考帧中某位置的(重建后)数据保存进cache,供参考和反复使用。 x264_macroblock_cache_s…

建站的方式有哪些创建一个餐饮公司的模板

1. Webpack 当前Web开发面临的困境 文件依赖关系错综复杂静态资源请求效率低模块化支持不友好浏览器对高级JavaScript特性兼容程度低 1.1 webpack概述 webpack是一个流行的前端项目构建工具,可以解决当前web开发中所面临的困境. webpack提供了友好的模块化支持,以及代码压…

旅游网站模板源码驻马店阿里巴巴做网站

XXXXXX.datagrid({url: "${pageContext.request.contextPath}/xx/xx/xx,});用上述方式动态加载datagrid的数据时,通过net监听,发现调用了两遍XX方法,目前的解决方案是,将url放到datagrid初始化的时候执行。$(#XXXX).datagrid…

柳州市建设工程质量安全监督管理处网站建设银行手机不用了怎么登陆网站

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

做电子商务网站注册哪一类商标浙江建设厅网站官网

内容摘要:基于信号到达角度(AOA)的定位算法是一种常见的无线传感器网络节点自定位算法,算法通信开销低,定位精度较高。由于各种原因,估测的多个节点位置可能存在不可靠位置,提出了一种改进的基于信号到达角的定位方法&…

电子商务如何做网站销售wordpress禁止自动更新

🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:泥中に咲く—ウォルピスカーター 0:34━━━━━━️💟──────── 4:46 🔄 ◀️ ⏸ ▶…

计算机考试模拟网站怎么做网站404页面设置

在mysql数据库中,null是一个经常出现的情况,关于mysql中的null,有哪些注意事项呢?下面简单总结归纳下,后续会不断补充。1. is null首先判断数据库中某一列的值是否为null,不能用等于来判断,必须…

做网站的怎么赚钱做网站对客户有什么帮助

类和对象面试题 1. & 和 && 的区别 参考答案 & 运算符有两种用法:(1) 按位与;(2) 逻辑与。&& 运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是 true 整个表达式的…

系网站的开发和建设毕业设计为什么很少人敢娶外贸女

软考高级系统架构设计师系列之:深入理解设计模式 一、设计模式相关技术文章二、设计原则三、设计模式概念四、设计模式的分类五、创建性模式六、创建性模式-工厂方法模式七、创建性模式-抽象工厂模式八、创建性模式-构建器模式九、面向对象设计-结构性模式十、结构性模式-适配…

保健食品东莞网站建设注册域名卖钱很暴利吗

说在前面 🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。 题目描述 给你一个下标从 0 开始、大小为 m x n 的矩阵 grid ,矩阵由若干 正 整数组成。 …

淮阴网站建设做报价在哪个网站询价

FL Studio 21.2 带有 stem 分离和 FL Cloud,这是一项专为 FL Studio 打造的具有里程碑意义的新服务。其他新功能包括 FL Studio Fruity Edition 的 Audio Clips(音频剪辑)和一个新的模拟建模合成器 Kepler。 为庆祝 FL Studio 21.2 的发布&am…

qq空间网站网站关键词库怎么做

[react] componentWillUpdate可以直接修改state的值吗 1: 不行,这样会导致无限循环报错。 2:在react中直接修改state,render函数不会重新执行渲染,应使用setState方法进行修改 个人简介 我是歌谣,欢迎和大家一起交流…

先做网站后台还是前台百度广告代理商

ConcurrentHashMap ConcurrentHashMap的整体架构ConcurrentHashMap的基本功能ConcurrentHashMap在性能方面的优化 concurrentHashMap: ConcurrentHashMap的整体架构 concurrentHashMap是由数组链表红黑树组成 当我们初始化一个ConcurrentHashMap实例时&#xff0c…

营销活动网站有了域名后怎样做网站

动态内存管理 我们之前要开辟内存用的方法都是定义变量,比如 但是上述开辟内存的方法有两个特点 1空间开辟大小是固定的 2数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配 malloc和free c中提供一个动态内存开辟函数 这…

怎么自己制作网站平台产看网站权重

1. RestClient ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。官方文档地址:Elasticsearch Clients | Elastic 其中的Java Rest Client又包括两种: Java Low Level Res…

从衡阳麻衣事件到AI元人文:用户端元人文实践的进化路径研究——声明ai研究

从"衡阳麻衣事件"到AI元人文:用户端元人文实践的进化路径研究 一、引言:数字时代的人文觉醒 在2025年的中国衡阳,一场看似普通的"麻衣陈情"事件引发了AI领域的深刻反思,成为推动AI元人文构想诞…

深圳网络公司网站网站服务器不稳定怎么打开网页

mac 默认安装了python2;自己后面又安装了python3;为了方便,现在想将python3换成Anaconda3。 Anaconda是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。 Python3安装之后,在系统中不同目…

小型手机网站建设推荐wordpress 标签输出

LTspice(14) Noise仿真 好久没有更新LTspice的教程了,大家想了没? 截止目前LTspice已经更新到24.0.9。界面发生了一些变化,但主要功能并不受影响,新的版本改了UI,找东西更加方便了,界面如下图1所示。 图1…

深圳龙岗做网站的公司网站版面设计流程包括哪些

帕金森病是一种常见的神经系统变性疾病,其患病率在不同国家和地区存在一定的差异。根据流行病学调查,帕金森病的患病率随着年龄的增长而增加,平均发病年龄为60岁左右。在中国,65岁以上人群的帕金森病患病率大约是1.7%,…