存储过程、触发器和游标是数据库编程常用技术,对数据库应用系统开发意义重大,虽在不同系统中定义有别但原理相似,本章以 SQL Server 2008 为例介绍其概念与使用方法。

5.1存储过程

1、概念

存储过程是数据库编程中的关键概念。它是一组为实现特定功能而组合的 SQL 语句集合。这些语句经编译后存储在数据库内,用户可通过特定调用方式执行。存储过程具有以下特性:

  • 名称:方便用户识别与调用。
  • 参数:用于接收外部传入数据,增强处理灵活性。
  • 返回值:将处理结果反馈给调用者。
  • 嵌套调用:一个存储过程可调用另一个存储过程,提升功能的复杂度与灵活性。
2、分类
  1. 系统存储过程:由数据库系统自带,主要执行系统级操作,例如管理数据库、获取系统信息等。
  2. 扩展存储过程:允许用户使用外部语言(如 C 语言)编写函数,并集成到数据库中,以实现更复杂功能。
  3. 用户自定义存储过程:由用户依据自身业务需求编写,用于处理特定业务逻辑,满足个性化需求。不同类型的存储过程在数据库管理与应用开发中均发挥重要作用 。
3、优点

快速执行、安全性好、访问统一、命名代码,允许延迟绑定、减少网络通信流量

4、SQL注入攻击
  1. SQL 注入攻击原理

SQL 注入攻击是攻击者在应用程序的输入字段中插入恶意 SQL 代码,使应用程序构造出错误的 SQL 语句,从而欺骗数据库执行非预期操作 。当应用程序没有对用户输入进行严格验证和过滤时,攻击者输入的恶意代码就可能被当作 SQL 语句的一部分执行。

  1. 结合代码示例分析
  • 原始代码意图:代码本意是根据用户输入的用户名(txtusername 变量)和密码(txtpsd 变量),从 users 表中查询匹配的用户记录。构造的 SQL 语句如 select * from users where username='"+txtusername+"' and psd='"+txtpsd+"' ,正常情况下,它会筛选出用户名和密码都匹配的用户。
  • 恶意输入与攻击过程:图中攻击者输入 123 作为用户名,同时在用户名输入框中注入了 or 1=1 --or 1=1 是一个恒成立的条件(因为 1=1 永远为真 ),-- 是 SQL 中的注释符,用于注释掉后面的内容。这样,原本的 SQL 查询语句拼接后变为 select * from users where username='123 or 1=1 --' and psd='123' ,经数据库解析执行时,-- 后的 and psd='123' 被注释掉,实际执行的语句相当于 select * from users where username='123' or 1=1 ,由于 or 1=1 恒成立,所以会返回 users 表中的所有记录,攻击者无需正确密码就能绕过登录验证 。
  1. 可能造成的危害
  • 数据泄露:攻击者可获取敏感用户信息,如用户名、密码、个人资料等。
  • 非法操作:若攻击者权限足够,可能执行插入、修改、删除数据等操作,破坏数据库的完整性和可用性 。
  • 权限提升:进一步获取更高权限,控制数据库甚至服务器,对系统造成更严重破坏。
  1. 防范措施
  • 参数化查询:将 SQL 代码与用户输入分离,使输入仅作为数据处理,而非 SQL 代码的一部分。如在 SQL Server 中使用 SqlParameter 类。
  • 输入验证和过滤:对用户输入进行严格检查,过滤掉特殊字符和 SQL 关键字,阻止恶意代码注入。
  • 最小权限原则:数据库用户仅分配必要的权限,降低攻击造成的损失。
5、存储过程与函数的区别如下:
  • 执行效率:存储过程是预编译的,执行效率比函数高 。
  • 返回值:存储过程可以不返回任何值,也能通过多个输出变量返回结果;函数则有且必须有一个返回值 。
  • 使用方式:存储过程必须单独执行;函数可以嵌入到表达式中,使用更灵活 。
  • 应用场景:存储过程主要用于逻辑处理;函数主要用于实现特定功能 。
6、创建存储过程

在这里插入图片描述

  1. 语法格式
CREATE PROCEDURE <过程名>
AS
<SQL语句>
  1. 示例:在学生 - 课程数据库中创建一个存储过程,检索学分超过 3 的课程名称及选修该课程的学生姓名、所在系和成绩。
CREATE PROCEDURE Query_Grade
AS
SELECT Cname,Sname,Sdept,Grade
FROM Student S,Course C,SC
WHERE S.Sno=SC.Sno AND SC.Cno=C.Cno AND Ccredit>3;
7、执行存储过程
  1. 语法格式
[EXEC[UTE]][@返回状态变量=]<过程名> 
[[@参数1=]1|@变量1 [OUT[PUT]]
 [,[@参数2=]2|@变量2 [OUT[PUT]][,]
[WITH RECOMPILE][;]

其中,OUTPUT指定存储过程将值送入输出参数;WITH RECOMPILE表示执行该存储过程时强制重新编译。

  1. 示例
  • 无参数存储过程执行:直接使用EXEC Query_Grade
  • 带参数存储过程执行:创建带参数的存储过程,通过输入学生姓名,检索该学生的平均成绩。
CREATE PROCEDURE Query_Avggrade
  @Sname CHAR(20)
AS
SELECT S.Sno,Sname,Avg(Grade) Avggrade 
FROM Student S,SC
WHERE S.Sno=SC.Sno AND Sname=@Sname;

调用方式:

  • 使用常量调用:EXEC Query_Avggrade '赵晨'EXEC Query_Avggrade @Sname = '赵晨'
  • 使用变量调用:
DECLARE @InputSname CHAR(20)
SELECT @InputSname ='赵晨'
EXEC Query_Avggrade @InputSname
8、修改和删除存储过程

在这里插入图片描述

  1. 修改存储过程
    • 语法格式
ALTER PROC[EDURE] <过程名>
[@参数1 数据类型 [=默认值]][OUT|OUTPUT][READONLY]
[,@参数2 数据类型 [=默认值]][OUT|OUTPUT][READONLY][,]   
[WITH ENCRYPTION]
AS {<T-SQL语句>[;]};

其参数及保留字含义与CREATE PROCEDURE相同。

  1. 删除存储过程
  • 语法格式DROP PROC[EDURE] <过程名>;
9、输出raiserror和print

在 SQL Server 中,RAISERROR(在 SQL Server 2012 及之后版本建议使用 THROW)和 PRINT 都可以用来输出信息,但它们的用途和特点有所不同,下面详细介绍:

RAISERROR

RAISERROR 用于生成错误信息并将其返回给应用程序或客户端。它不仅可以输出错误消息,还能指定错误的严重级别和状态,从而影响程序的执行流程。在你的示例中,RAISERROR('该学号不存在选课记录', 16, 1); 用于抛出一个错误信息。

用途
  • 错误处理:在存储过程、触发器或批处理中,当遇到不符合业务规则的情况时,可以使用 RAISERROR 抛出错误,通知调用者发生了异常。
  • 事务回滚:如果错误严重级别设置为 11 及以上,会触发事务回滚,保证数据的一致性。
参数解释
  • 第一个参数:是错误消息的文本内容,如 '该学号不存在选课记录'
  • 第二个参数:是错误的严重级别,范围从 0 到 25。16 表示一般错误,通常用于用户定义的错误。
  • 第三个参数:是错误的状态码,范围从 1 到 127,用于标识错误发生的位置或上下文。
PRINT

PRINT 用于将文本消息输出到客户端的消息窗口,它不会影响程序的执行流程,也不会触发事务回滚。

用途
  • 调试信息输出:在开发和调试过程中,可以使用 PRINT 输出中间结果或变量值,帮助你理解程序的执行过程。
  • 状态信息提示:在存储过程或批处理中,输出一些操作的状态信息,让用户了解程序的执行进度。
两者区别
比较项 RAISERROR PRINT
对程序流程的影响 严重级别 11 及以上会触发事务回滚,并且可能导致程序中断执行 不影响程序的执行流程
消息类型 主要用于输出错误消息,可携带错误级别和状态信息 用于输出普通的文本消息
应用场景 用于业务规则检查失败、数据异常等情况,通知调用者发生错误 用于调试代码、输出操作状态信息等
示例代码
-- 创建一个简单的存储过程,演示 RAISERROR 和 PRINT 的使用
CREATE PROCEDURE CheckStudentCourses
    @studentID INT
AS
BEGIN
    -- 检查是否存在选课记录
    IF NOT EXISTS (SELECT 1 FROM CourseEnrollments WHERE StudentID = @studentID)
    BEGIN
        -- 使用 RAISERROR 抛出错误
        RAISERROR('该学号不存在选课记录', 16, 1);
        RETURN;
    END

    -- 输出操作成功的信息
    PRINT '该学号存在选课记录,操作继续...';
    -- 这里可以继续执行其他操作
END;
十、存储过程的参数及返回值

在这里插入图片描述

  • 输入参数

    :供调用程序向存储过程传送数据,需定义变量名和类型,可设默认值,值能为常量或变量值。

    • 例如,创建存储过程 Query_Avgggrade,通过输入学生姓名(输入参数 @Sname)检索其平均成绩,定义如下:
CREATE PROCEDURE Query_Avgggrade
    @Sname CHAR(20)
AS
-- 具体查询逻辑
SELECT S.Sno, Sname, Avg(Grade) Avggrade
FROM Student S, SC
WHERE S.Sno = SC.Sno AND Sname = @Sname
--GROUP BY S.Sno,Sname;
  • 调用时可用常量,如:
EXEC Query_Avgggrade '赵晨'
  • 也可用变量,先声明变量,再赋值,最后执行:
DECLARE @InputSname CHAR(20)
SELECT @InputSname = '赵晨'
EXEC Query_Avgggrade @InputSname
  • 输出参数:用

    OUTPUT
    

    关键字声明,让存储过程能将数据或游标变量传回调用程序。

    • 例如,Query_Grade_OUT 存储过程,通过学号查找学生平均成绩并输出,定义如下:
CREATE PROCEDURE Query_Grade_OUT
    @Sno CHAR(9),
    @AvgGrade SMALLINT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    SELECT @AvgGrade = AVG(Grade) FROM SC WHERE Sno = @Sno;
END
  • 执行时:
DECLARE @OutAvg SMALLINT
EXEC Query_Grade_OUT '201215121', @OutAvg OUTPUT
SELECT @OutAvg
  • 参数传递:
    • 按参数位置传递:按参数顺序依次传入值。例如 Query_Student 存储过程,查询姓赵学生信息时:
EXEC Query_Student '', '赵'
  • 按参数名字传递:以参数名指定值,参数顺序任意,灵活性高。例如:
EXEC Query_Student @Sname = '赵'

按名字传递参数比按位置具有更大的灵活性,但按位置传递参数速度更快。

存储过程的返回值

  • 使用 RETURN 语句指定返回代码。返回值在 -1 到 -99 间表示执行未成功;大于 0 或小于 -99 的整数可作自定义返回值,标识不同执行结果。

  • Check_Student
    

    存储过程为例,根据学号判定学生是否存在,自定义返回值含义为:0 表示学生存在;1 表示学生不存在;2 表示未指定所需参数;3 表示获取数据出错。

    • 定义如下:
CREATE PROCEDURE Check_Student
    @Sno CHAR(9) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @Scount INT;
    IF @Sno IS NULL RETURN (2);
    SELECT @Scount = COUNT(*) FROM Student WHERE Sno = @Sno;
    IF @@ERROR<>0 RETURN(3);
    IF @Scount>0 RETURN(0) ELSE RETURN(1);
END
  • 执行代码通过判断返回值输出对应信息:
DECLARE @Sno CHAR(9), @nRtn INT
SELECT @Sno = '201215128'
EXECUTE @nRtn = Check_Student @Sno
IF @nRtn = 0
    PRINT '学号为'+@Sno+'的学生存在!'
ELSE IF @nRtn = 1
    PRINT '学号为'+@Sno+'的学生不存在!'
ELSE IF @nRtn = 2
    PRINT '必需输入学号!'
ELSE IF @nRtn = 3
    PRINT '获取数据出错!'
ELSE
    PRINT '其他错误!'

5.2触发器

1. 触发器基础
  1. 定义:触发器是一种特殊的存储过程,当在指定的数据表中对数据进行插入、修改以及删除操作时,会自动执行对应的触发器代码。它为数据库提供了有效的监控和处理机制,确保数据和业务的完整性。
  2. 分类
    • 按触发事件分类
      • DML 触发器:响应 INSERTDELETEUPDATE 操作,用于在数据操作时自动执行特定逻辑。
      • DDL 触发器:响应数据定义语言操作,如创建、修改或删除数据库对象等。
      • 登录触发器:在用户登录 SQL Server 实例时触发。
    • 按触发执行方式分类
      • AFTER 触发器(后触发器):在触发事件成功执行后触发,可用于数据验证、日志记录等。
      • INSTEAD OF 触发器(前触发器):替代触发事件执行,常用于视图等不支持直接 DML 操作的对象上。
2. 触发器的优缺点
  1. 优点
    • 强化约束功能:能实现比普通约束更复杂的数据完整性规则,如跨表数据验证。
    • 跟踪数据变化:方便记录数据的变更情况,可用于审计等场景。
    • 支持级联运行:一个触发器执行后可触发其他相关操作,实现复杂业务逻辑。
    • 可调用存储过程:在触发器中可调用存储过程,进一步拓展功能。
  2. 局限性
    • 性能问题:每次触发事件发生都要执行触发器代码,可能导致性能下降。
    • 维护困难:过多或不恰当使用触发器,会使数据库逻辑复杂,难以理解和维护。
3. SQL SERVER DML 触发器
  1. INSERT 触发器:在数据插入表或视图时执行。新插入的数据行同时会插入到 inserted 虚拟表,该表保存插入数据行副本,用于对比插入前后数据变化。
  2. DELETE 触发器:执行删除操作时触发。被删除的数据先存放在 deleted 虚拟表,用于引用已删除数据,deleted 表和原表通常无相同行。
  3. UPDATE 触发器:数据修改时触发。处理分两步,原始数据移到 deleted 表,修改后数据插入 inserted 表,触发器据此检查并更新数据表。
4. 触发器创建语法总结

在 SQL Server 中,创建触发器的基本语法如下:

CREATE TRIGGER [schema_name.]trigger_name
ON {table_name | view_name}
[WITH ENCRYPTION]
{FOR | AFTER | INSTEAD OF} {[INSERT] [, ] [UPDATE] [, ] [DELETE]}
AS
BEGIN
    -- 具体的 T - SQL 操作语句
    -- 可包含多条语句,用于实现特定逻辑
END;
  • [schema_name.]trigger_name:指定触发器的名称,schema_name 为架构名,可省略。
  • ON {table_name | view_name}:指定触发器作用的表或视图。
  • [WITH ENCRYPTION]:可选参数,对触发器定义进行加密。
  • {FOR | AFTER | INSTEAD OF}:确定触发时机和方式。FORAFTER 表示在触发操作成功执行后触发;INSTEAD OF 表示替代触发操作执行。
  • {[INSERT] [, ] [UPDATE] [, ] [DELETE]}:指明触发触发器的操作类型,可多选。
  • AS 之后的 BEGIN...END 块内编写具体执行的 T - SQL 代码。
5. 示例及解析
5.1. 维护选课人数一致性(DML 触发器)
-- 创建用于记录课程号及其选课人数的表
CREATE TABLE Course_Num(
    Cno CHAR(4) PRIMARY KEY,
    Ccount SMALLINT
);
-- 初始化表数据
INSERT INTO Course_Num
SELECT Cno, COUNT(*) FROM SC GROUP BY Cno;

-- 创建触发器
CREATE TRIGGER Tri_Course_Count
ON SC
FOR INSERT, DELETE, UPDATE
AS
BEGIN
    UPDATE Course_Num
    SET Ccount = (SELECT COUNT(*) FROM SC WHERE SC.Cno = Course_Num.Cno)
    WHERE Cno IN (SELECT Cno FROM deleted) OR Cno IN (SELECT Cno FROM inserted);
END;

解析

  • 先创建 Course_Num 表并初始化数据。
  • Tri_Course_Count 触发器作用于 SC 表,当 SC 表发生 INSERTDELETEUPDATE 操作时触发。
  • 触发器内部通过 UPDATE 语句,依据 inserted(插入或更新后的数据)和 deleted(删除或更新前的数据)虚拟表中的课程号,重新统计并更新 Course_Num 表中的选课人数,保证数据一致性。
5.2. 限制成绩非空时删除选课记录(DML 触发器)
CREATE TRIGGER Tri_SC_Del
ON SC
AFTER DELETE
AS
BEGIN
    IF EXISTS (SELECT * FROM deleted WHERE Grade IS NOT NULL)
    BEGIN
        PRINT '成绩非空,不能删除!';
        ROLLBACK TRANSACTION;
    END
END;

解析

  • Tri_SC_Del 触发器在 SC 表执行 DELETE 操作之后触发。
  • 利用 IF EXISTS 语句检查 deleted 虚拟表中是否存在成绩非空的记录。若存在,使用 PRINT 输出提示信息,并用 ROLLBACK TRANSACTION 回滚事务,撤销删除操作,维护数据完整性。
5.3. 年龄修改约束(DML 触发器)
CREATE TRIGGER Tri_Student_Update
ON Student
AFTER UPDATE
AS
BEGIN
    IF UPDATE(Sage)
        IF EXISTS (SELECT I.* FROM inserted I, deleted D WHERE I.Sno = D.Sno AND I.Sage < D.Sage)
        BEGIN
            PRINT '新年龄小于原来年龄,不能修改!';
            ROLLBACK TRANSACTION;
        END
END;

解析

  • Tri_Student_Update 触发器作用于 Student 表,在 UPDATE 操作之后触发。
  • UPDATE(Sage) 函数判断是否对年龄字段 Sage 进行了修改。若修改,进一步检查 inserted 虚拟表(更新后数据)中同学生的新年龄是否小于 deleted 虚拟表(更新前数据)中的原年龄。若满足条件,输出提示信息并回滚事务,实现年龄修改的业务规则约束。
5.4. 基于视图更新(INSTEAD OF 触发器)
-- 创建视图
CREATE VIEW V_Birth(Sno, Sname, BirthYear)
AS
SELECT Sno, Sname, YEAR(GETDATE()) - Sage FROM Student;

-- 创建 INSTEAD OF 触发器
CREATE TRIGGER Tri_VBirth
ON V_Birth
INSTEAD OF UPDATE
AS
BEGIN
    IF UPDATE(BirthYear)
    BEGIN
        UPDATE Student
        SET Sage = YEAR(GETDATE()) - I.BirthYear
        FROM inserted I
        WHERE I.Sno = Student.Sno;
    END
END;

解析

  • 先创建 V_Birth 视图,视图中通过当前年份减去学生年龄计算出生年份。
  • Tri_VBirthINSTEAD OF 触发器,作用于 V_Birth 视图。当尝试更新视图中的出生年份时,触发器触发。
  • 触发器内部通过 UPDATE 语句,根据 inserted 虚拟表(更新后的数据)中的信息,更新基表 Student 中的年龄字段,解决视图有导出列时无法直接更新的问题。

5.3游标

5.3.1、游标定义

游标(Cursor)是关系数据库中处理结果集的一种机制,用于支持对结果集的逐行操作。在 SQL Server 中,游标本质上是一个指向查询结果集的指针,允许应用程序对结果集中的每一行数据进行单独处理,弥补了 SQL 语句一次处理整个行集的局限性。

5.3.2、核心作用
  1. 逐行处理数据
    对结果集中的每行数据进行独立操作(如更新、删除或复杂计算),适用于需要逐行遍历的业务场景(如报表生成、数据校验)。
  2. 定位数据行
    在结果集中定位特定行,支持向前、向后或随机滚动(需定义为可滚动游标)。
  3. 支持数据修改
    通过游标直接修改基表数据(需声明为可更新游标),实现定位更新或删除。
  4. 处理复杂逻辑
    在存储过程、触发器中结合循环结构(如 WHILE)处理多行数据,扩展 SQL 的编程能力。
5.3.3、游标分类
  1. 按滚动特性分类
    • 静态游标(Static Cursor)
      生成游标时将结果集静态存储,后续对基表的修改不会反映到游标中。
    • 动态游标(Dynamic Cursor)
      实时反映基表数据的变化,游标中的数据会随基表更新而动态调整。
    • 键集驱动游标(Keyset-Driven Cursor)
      基于唯一标识(主键)定位行,结果集行数固定,但行数据可能随基表更新而变化。
    • 快速前向游标(Fast-Forward Cursor)
      仅支持向前滚动,性能较高,是默认的游标类型。
  2. 按更新特性分类
    • 只读游标(READ ONLY)
      禁止通过游标修改基表数据。
    • 可更新游标(UPDATE)
      允许使用 WHERE CURRENT OF 子句对游标当前行进行更新或删除。
5.3.4、游标操作步骤
  1. 声明游标(DECLARE)
    定义游标名称、关联的查询语句及特性(如滚动性、更新性)。
    语法示例(T-SQL)

    DECLARE @cursor_name CURSOR  
    [LOCAL|GLOBAL] -- 作用域(局部/全局)  
    [FORWARD_ONLY|SCROLL] -- 滚动方向(仅向前/可滚动)  
    [STATIC|KEYSET|DYNAMIC|FAST_FORWARD] -- 类型  
    [READ_ONLY|SCROLL_LOCKS|OPTIMISTIC] -- 更新特性  
    FOR <SELECT语句>;  
    
  2. 打开游标(OPEN)
    执行查询并填充结果集,此时游标指向结果集的第一行之前。

    OPEN @cursor_name;  
    
  3. 提取数据(FETCH)
    使用 FETCH 语句逐行获取数据,并通过全局变量 @@FETCH_STATUS 检查操作状态:

    • 0:成功
    • -1:超出结果集范围
    • -2:行已删除
      滚动操作示例
    FETCH NEXT FROM @cursor_name; -- 下一行(默认)  
    FETCH PRIOR FROM @cursor_name; -- 上一行  
    FETCH ABSOLUTE 5 FROM @cursor_name; -- 绝对定位第5行  
    FETCH RELATIVE -2 FROM @cursor_name; -- 相对当前行向前2行  
    
  4. 处理数据
    对提取的行数据进行业务逻辑处理(如计算、更新基表)。

  5. 关闭游标(CLOSE)
    释放游标占用的系统资源,但保留游标定义,可通过 OPEN 重新激活。

    CLOSE @cursor_name;  
    
  6. 释放游标(DEALLOCATE)
    永久删除游标,释放内存空间。

    DEALLOCATE @cursor_name;  
    
5.3.5、典型应用场景
  1. 逐行数据更新
    例如,根据学生所在系别调整成绩(如 CS 系加 5 分,IS 系加 10 分)。

    DECLARE @sno CHAR(9), @dept CHAR(2);  
    DECLARE cur_Student CURSOR FOR  
      SELECT Sno, Sdept FROM Student;  
    OPEN cur_Student;  
    FETCH NEXT FROM cur_Student INTO @sno, @dept;  
    WHILE @@FETCH_STATUS = 0  
    BEGIN  
      UPDATE SC SET Grade = Grade + CASE @dept  
        WHEN 'CS' THEN 5  
        WHEN 'IS' THEN 10  
        ELSE 15  
      END WHERE Sno = @sno;  
      FETCH NEXT FROM cur_Student INTO @sno, @dept;  
    END;  
    CLOSE cur_Student;  
    DEALLOCATE cur_Student;  
    
  2. 报表生成与统计
    遍历结果集并拼接成特定格式的报表数据(如按序号输出课程信息)。

  3. 数据校验与业务规则
    逐行验证数据完整性(如检查订单金额是否超过信用额度)。

5.3.6、优缺点分析
  • 优点
    • 灵活性高:支持逐行处理和复杂逻辑。
    • 兼容性强:适用于无法用集合操作完成的场景。
  • 缺点
    • 性能开销大:逐行操作效率低于集合操作,尤其对大数据集。
    • 维护复杂:游标代码可读性较差,易引发资源泄漏(如未关闭或释放游标)。
    • 阻塞问题:默认情况下,游标会锁定数据行,可能影响并发性能。
5.3.7、最佳实践
  1. 优先使用集合操作
    能用 UPDATE/DELETE 配合 WHERE 子句完成的操作,避免使用游标。
  2. 限制结果集大小
    在声明游标时通过 WHERE 子句过滤数据,减少处理行数。
  3. 选择合适的游标类型
    • 仅向前滚动:使用 FAST_FORWARD(性能最优)。
    • 只读场景:声明为 READ ONLY
    • 需滚动:启用 SCROLL 并谨慎使用定位操作。
  4. 及时释放资源
    确保每次使用游标后执行 CLOSEDEALLOCATE,避免内存泄漏。
5.3.8、游标与存储过程 / 触发器的结合

游标常嵌入存储过程或触发器中,用于处理需要逐行逻辑的业务。例如:

  • 在存储过程中遍历订单数据,计算累计金额。
  • 在触发器中逐行验证插入数据的合法性(如库存是否充足)。

通过合理使用游标,可以在保持数据库性能的前提下,实现复杂的业务逻辑。

Logo

「智能机器人开发者大赛」官方平台,致力于为开发者和参赛选手提供赛事技术指导、行业标准解读及团队实战案例解析;聚焦智能机器人开发全栈技术闭环,助力开发者攻克技术瓶颈,促进软硬件集成、场景应用及商业化落地的深度研讨。 加入智能机器人开发者社区iRobot Developer,与全球极客并肩突破技术边界,定义机器人开发的未来范式!

更多推荐