说道游标,我想大家并不陌生。但对于我们大多数初学者来说,就未必用过游标了。下面我就以一个实际例子给大家说一下我们为什么要用游标、什么时候用、怎么用。
实例:某学校有多个班级,而每个班级里有多个学生。现在我们要完成这样一件事,假如有一天,这个学校不存在了,那么属于这个学校的班级也就不存在了,同理,这些班里的学生也就不再属于这个班了。
需求明白了,我们开始建表,表结构如下:
注:IsAvailable字段值为否时标明该条记录不存在。
在Class表中建立如下触发器:
Perfect,到此为止,我们的工作貌似要结束了,插入如下数据,测试一下。
分析:从结果可以看出,我们的设计逻辑没有任何问题。两个触发器也被触发了,可结果为何不是我们想要的呢?仔细分析你会发现Class表下的触发器执行了,但是貌似只执行了一次,这就是问题所在之处。那么我们怎么能让每一条更新语句都触发更新触发器呢?此时,咱们今天的主角就要登场了,下面有请“游标”先生闪亮登场。
下面我将直接修改School表下的触发器,里面将用到游标,并附有详细的注释,相信你会看懂的。
School表下修改后的触发器代码:
到此为止,我相信大家应该清楚为何用游标、什么时候用、怎么用这三个问题了。希望对大家有帮助。
实例:某学校有多个班级,而每个班级里有多个学生。现在我们要完成这样一件事,假如有一天,这个学校不存在了,那么属于这个学校的班级也就不存在了,同理,这些班里的学生也就不再属于这个班了。
需求明白了,我们开始建表,表结构如下:
![](https://img-my.csdn.net/uploads/201301/02/1357113592_3543.png)
为了实现上述功能,我们决定用触发器,于是在School表中建立触发器,具体语句如下:
CREATE TRIGGER [dbo].[UpdateClass]
ON [dbo].[School]
AFTER UPDATE
AS
DECLARE
@schoolID INT,--学校ID
@isAvailable CHAR(2)--是否可用
BEGIN
--查询出更新记录的SchoolID和IsAvailable字段值
SELECT @schoolID=SchoolID, @isAvailable=IsAvailable FROM inserted
--如果更新的是isAvailable并且更新后的字段值是否
if (UPDATE(isAvailable) and @isAvailable = '否')
--标示该学校所有班级不可用(班级表中IsAvailable字段值为否)
UPDATE Class SET IsAvailable='否' WHERE SchoolID=@schoolID
END
在Class表中建立如下触发器:
CREATE TRIGGER [dbo].[UpdateStudent]
ON [dbo].[Class]
AFTER UPDATE
AS
DECLARE
@classID INT,--班级ID
@isAvailable CHAR(2)--是否可用
BEGIN
--查询出更新记录的ClassID和IsAvailable字段值
SELECT @classID=ClassID, @isAvailable=IsAvailable FROM inserted
--如果更新的是isAvailable并且更新后的字段值是否
IF (UPDATE(isAvailable) and @isAvailable = '否')
--更新该班级下的所有学生IsAvailable字段值为否
UPDATE Student SET IsAvailable='否' WHERE ClassID=@classID
END
Perfect,到此为止,我们的工作貌似要结束了,插入如下数据,测试一下。
![](https://img-my.csdn.net/uploads/201301/02/1357113735_3325.png)
执行假删除语句:
UPDATE School SET IsAvailable='否' WHERE SchoolID = 1
结果如下:
![](https://img-my.csdn.net/uploads/201301/02/1357113789_4603.png)
下面我将直接修改School表下的触发器,里面将用到游标,并附有详细的注释,相信你会看懂的。
School表下修改后的触发器代码:
ALTER TRIGGER [dbo].[UpdateClass]
ON [dbo].[School]
AFTER UPDATE
AS
DECLARE
@schoolID INT,--学校ID
@ClassID INT,--班级ID
@isAvailable CHAR(2)--是否可用
BEGIN
--查询出更新记录的SchoolID和IsAvailable字段值
SELECT @schoolID=SchoolID, @isAvailable=IsAvailable FROM inserted
--如果更新的是isAvailable并且更新后的字段值是否
IF (UPDATE(isAvailable) AND @isAvailable = '否')
BEGIN
--声明游标(集合为删除学校下的班级ID)
DECLARE ClassCursor CURSOR FOR
SELECT ClassID FROM Class WHERE SchoolID = @schoolID
--打开游标
OPEN ClassCursor
--当游标被打开时,行指针将指向该游标集第1行之前。
--如果要读取游标集中的第1行数据,必须移动行指针使其指向第1行。
FETCH NEXT FROM ClassCursor INTO @ClassID --给变量赋初始值(游标中第一行数据)
--每执行一个FETCH操作之后,查看一下全局变量@@FETCH_STATUS中的状态值,以此判断FETCH操作是否成功。
--变量@@FETCH_STATUS有三种状态值:
-- 0 表示成功执行FETCH语句。
-- -1 表示FETCH语句失败,例如移动行指针使其超出了结果集。
-- -2 表示被提取的行不存在。
WHILE @@FETCH_STATUS=0 --语句执行成功
BEGIN
--标识该学校所有班级不可用(班级表中IsAvailable字段值为否)
UPDATE Class SET IsAvailable='否' WHERE ClassID=@ClassID
--读取游标中下一条数据,并赋值给@ClassID
FETCH NEXT FROM ClassCursor INTO @ClassID
END
--关闭并释放游标
CLOSE ClassCursor
DEALLOCATE ClassCursor
END
END
当我们再次执行
假删除学校操作时,你会发现问题完美解决了。结果如下:
![](https://img-my.csdn.net/uploads/201301/02/1357113905_2463.png)
到此为止,我相信大家应该清楚为何用游标、什么时候用、怎么用这三个问题了。希望对大家有帮助。