注册
达梦数据库的存储过程语法
技术分享/ 文章详情 /

达梦数据库的存储过程语法

何处惹尘埃 2026/08/07 101 0 0

问题10:存储过程语法。如何调试存储过程?

一、存储过程概述

存储过程是预编译的SQL代码块,存储在数据库中,可以通过名称调用执行。存储过程可以包含SQL语句、流程控制、变量声明、异常处理等,适合封装复杂的业务逻辑。存储过程支持参数传递,包括输入参数(IN)、输出参数(OUT)和输入输出参数(IN OUT)。

二、实操环境

  • 实例:TESTDB(端口 5239)
  • 测试用户:SYSDBA
  • 测试表:TEST.EMPLOYEE(已有约 100004 行数据)
  • 调试工具:DBMS_OUTPUT

三、存储过程基础操作

3.1 存储过程创建语法

CREATE OR REPLACE PROCEDURE 过程名(参数列表) AS -- 变量声明部分 变量名 数据类型; BEGIN -- 执行语句部分 SQL语句; EXCEPTION -- 异常处理部分(可选) WHEN 异常名 THEN 处理语句; END; /

创建存储过程的基本模板,包含变量声明、执行语句和异常处理三部分,以 / 结束创建。

3.2 创建无参数存储过程

CREATE OR REPLACE PROCEDURE TEST.PROC_HELLO AS BEGIN DBMS_OUTPUT.PUT_LINE('Hello, World!'); END; /

创建一个名为 PROC_HELLO 的存储过程,调用时输出 “Hello, World!”。

3.3 创建带输入参数的存储过程

CREATE OR REPLACE PROCEDURE TEST.PROC_GET_EMPLOYEE( p_id IN INT ) AS v_name VARCHAR(50); v_age INT; BEGIN SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; DBMS_OUTPUT.PUT_LINE('员工姓名: ' || v_name || ', 年龄: ' || v_age); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('未找到ID为 ' || p_id || ' 的员工'); END; /

传入员工ID(输入参数 p_id),查询对应员工的姓名和年龄并输出;如果ID不存在则捕获异常并提示。

3.4 创建带输出参数的存储过程

CREATE OR REPLACE PROCEDURE TEST.PROC_GET_EMPLOYEE_COUNT( p_dept IN VARCHAR, p_count OUT INT ) AS BEGIN SELECT COUNT(*) INTO p_count FROM TEST.EMPLOYEE WHERE DEPT = p_dept; END; /

传入部门名称(输入参数 p_dept),将对应部门的员工数量通过输出参数 p_count 返回给调用者。

四、存储过程的调试方法

4.1 启用 DBMS_OUTPUT

SET SERVEROUTPUT ON;

启用服务端输出功能,使 DBMS_OUTPUT.PUT_LINE 的输出能够显示在客户端。

4.2 使用 DBMS_OUTPUT 调试

CREATE OR REPLACE PROCEDURE TEST.PROC_DEBUG_DEMO( p_id IN INT ) AS v_name VARCHAR(50); v_age INT; BEGIN DBMS_OUTPUT.PUT_LINE('开始执行,输入参数 p_id=' || p_id); SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; DBMS_OUTPUT.PUT_LINE('查询结果: NAME=' || v_name || ', AGE=' || v_age); IF v_age > 30 THEN DBMS_OUTPUT.PUT_LINE('该员工年龄超过30岁'); ELSE DBMS_OUTPUT.PUT_LINE('该员工年龄不超过30岁'); END IF; DBMS_OUTPUT.PUT_LINE('执行结束'); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('异常: 未找到ID=' || p_id || '的记录'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('其他异常: ' || SQLERRM); END; /

在执行过程中通过 DBMS_OUTPUT.PUT_LINE 输出每一步的进度和变量值(开始、查询结果、判断结果、结束),方便追踪执行路径。

4.3 调用调试存储过程

CALL TEST.PROC_DEBUG_DEMO(1);

调用调试存储过程,输出每一步的执行情况,确认程序按预期路径运行。

实际输出

开始执行,输入参数 p_id=1
查询结果: NAME=张三, AGE=30
该员工年龄不超过30岁
执行结束
DMSQL 过程已成功完成

五、使用日志表持久化调试信息

5.1 创建日志表

CREATE TABLE TEST.PROC_LOG ( LOG_ID INT IDENTITY(1,1), PROC_NAME VARCHAR(100), LOG_TIME DATETIME DEFAULT SYSDATE, LOG_MSG VARCHAR(4000) );

创建日志表,包含自增ID、过程名、记录时间和消息内容,用于持久化存储存储过程的执行日志。

5.2 创建带日志记录的存储过程

CREATE OR REPLACE PROCEDURE TEST.PROC_DEBUG_WITH_LOG( p_id IN INT ) AS v_name VARCHAR(50); v_age INT; BEGIN -- 记录开始日志 INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '开始执行,p_id=' || p_id); SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; -- 记录查询结果 INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '查询结果: NAME=' || v_name || ', AGE=' || v_age); DBMS_OUTPUT.PUT_LINE('员工: ' || v_name || ', 年龄: ' || v_age); IF v_age > 30 THEN DBMS_OUTPUT.PUT_LINE('年龄超过30岁'); ELSE DBMS_OUTPUT.PUT_LINE('年龄不超过30岁'); END IF; -- 记录结束日志 INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '执行结束'); COMMIT; EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '异常: 未找到ID=' || p_id); DBMS_OUTPUT.PUT_LINE('未找到ID=' || p_id); WHEN OTHERS THEN INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '其他异常: ' || SQLERRM); DBMS_OUTPUT.PUT_LINE('异常: ' || SQLERRM); END; /

在执行过程中向 PROC_LOG 表插入开始、查询结果、结束三条日志记录,同时通过 DBMS_OUTPUT 输出信息到客户端;异常时也会记录异常日志。

5.3 验证日志记录

TRUNCATE TABLE TEST.PROC_LOG; CALL TEST.PROC_DEBUG_WITH_LOG(1); SELECT * FROM TEST.PROC_LOG ORDER BY LOG_ID;

清空日志表,执行存储过程查询 ID=1 的员工,然后查看日志表中记录的执行过程。

日志表输出

行号  LOG_ID  PROC_NAME              LOG_TIME                LOG_MSG
----- ------ ----------------------- ----------------------- --------------------------------
1     1       PROC_DEBUG_WITH_LOG    2026-08-03 09:18:18.000 开始执行,p_id=1
2     2       PROC_DEBUG_WITH_LOG    2026-08-03 09:18:18.000 查询结果: NAME=张三, AGE=30
3     3       PROC_DEBUG_WITH_LOG    2026-08-03 09:18:18.000 执行结束

六、存储过程的管理操作

6.1 删除存储过程

DROP PROCEDURE TEST.PROC_HELLO;

删除指定的存储过程。

6.2 查看存储过程定义

SELECT TEXT FROM USER_SOURCE WHERE NAME='PROC_DEBUG_WITH_LOG' AND TYPE='PROCEDURE';

查看存储过程的源代码。

七、调试方法对比

调试方法 优点 缺点 适用场景
DBMS_OUTPUT.PUT_LINE 即时反馈,无需额外表 只能在当前会话查看,无法持久化 开发阶段实时调试
日志表记录 持久化存储,可随时查询 需要创建表,存储过程需修改 生产环境问题追踪

八、常见问题处理

问题 原因 解决方法
DBMS_OUTPUT 无输出 未启用输出功能 执行 SET SERVEROUTPUT ON;
无效的变量名 在存储过程外部引用了局部变量 变量只能在存储过程内部使用,或在外部使用绑定变量
NO_DATA_FOUND 未触发 查询实际返回了数据 使用 SELECT COUNT(*) 先判断是否存在,再用 SELECT INTO

九、完整操作命令清单

-- 启用 DBMS_OUTPUT SET SERVEROUTPUT ON; -- 创建无参数存储过程 CREATE OR REPLACE PROCEDURE TEST.PROC_HELLO AS BEGIN DBMS_OUTPUT.PUT_LINE('Hello, World!'); END; / CALL TEST.PROC_HELLO(); -- 创建带输入参数的存储过程 CREATE OR REPLACE PROCEDURE TEST.PROC_GET_EMPLOYEE(p_id IN INT) AS v_name VARCHAR(50); v_age INT; BEGIN SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; DBMS_OUTPUT.PUT_LINE('员工: ' || v_name || ', 年龄: ' || v_age); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('未找到ID=' || p_id); END; / CALL TEST.PROC_GET_EMPLOYEE(1); -- 创建带调试输出的存储过程 CREATE OR REPLACE PROCEDURE TEST.PROC_DEBUG_DEMO(p_id IN INT) AS v_name VARCHAR(50); v_age INT; BEGIN DBMS_OUTPUT.PUT_LINE('开始执行,p_id=' || p_id); SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; DBMS_OUTPUT.PUT_LINE('查询结果: NAME=' || v_name || ', AGE=' || v_age); IF v_age > 30 THEN DBMS_OUTPUT.PUT_LINE('年龄超过30岁'); ELSE DBMS_OUTPUT.PUT_LINE('年龄不超过30岁'); END IF; DBMS_OUTPUT.PUT_LINE('执行结束'); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('异常: 未找到ID=' || p_id); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('其他异常: ' || SQLERRM); END; / CALL TEST.PROC_DEBUG_DEMO(1); -- 创建日志表 CREATE TABLE TEST.PROC_LOG ( LOG_ID INT IDENTITY(1,1), PROC_NAME VARCHAR(100), LOG_TIME DATETIME DEFAULT SYSDATE, LOG_MSG VARCHAR(4000) ); -- 创建带日志记录的存储过程 CREATE OR REPLACE PROCEDURE TEST.PROC_DEBUG_WITH_LOG(p_id IN INT) AS v_name VARCHAR(50); v_age INT; BEGIN INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '开始执行,p_id=' || p_id); SELECT NAME, AGE INTO v_name, v_age FROM TEST.EMPLOYEE WHERE ID = p_id; INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '查询结果: NAME=' || v_name || ', AGE=' || v_age); DBMS_OUTPUT.PUT_LINE('员工: ' || v_name || ', 年龄: ' || v_age); IF v_age > 30 THEN DBMS_OUTPUT.PUT_LINE('年龄超过30岁'); ELSE DBMS_OUTPUT.PUT_LINE('年龄不超过30岁'); END IF; INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '执行结束'); COMMIT; EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '异常: 未找到ID=' || p_id); DBMS_OUTPUT.PUT_LINE('未找到ID=' || p_id); WHEN OTHERS THEN INSERT INTO TEST.PROC_LOG(PROC_NAME, LOG_MSG) VALUES ('PROC_DEBUG_WITH_LOG', '其他异常: ' || SQLERRM); DBMS_OUTPUT.PUT_LINE('异常: ' || SQLERRM); END; / CALL TEST.PROC_DEBUG_WITH_LOG(1); SELECT * FROM TEST.PROC_LOG ORDER BY LOG_ID; -- 删除存储过程 DROP PROCEDURE TEST.PROC_HELLO;

十、总结

核心要点

  • 存储过程是封装SQL逻辑的代码块,支持输入输出参数
  • 调试时使用 DBMS_OUTPUT.PUT_LINE 即时输出变量值和执行状态,需先执行 SET SERVEROUTPUT ON;
  • 生产环境可使用日志表持久化记录执行过程,便于事后追踪
  • 异常处理使用 EXCEPTION 块,可捕获 NO_DATA_FOUNDOTHERS 等异常
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服