Oracle存储过程怎么写

Oracle 存储过程(Stored Procedure)是存储在数据库中的一组预编译 SQL 和 PL/SQL 代码块,用于封装复杂的业务逻辑。

以下是完整的编写指南,包含基本结构参数类型常用逻辑 以及完整示例

1. 基本语法结构

一个标准的存储过程由三部分组成:声明部分执行部分异常处理部分

sql 复制代码
CREATE OR REPLACE PROCEDURE 过程名 (
    参数1 IN 数据类型,      -- 输入参数
    参数2 OUT 数据类型,     -- 输出参数
    参数3 IN OUT 数据类型   -- 输入输出参数
) IS
    -- 【声明部分】定义局部变量、游标、常量等
    v_variable_name  VARCHAR2(100);
    v_count          NUMBER := 0;
BEGIN
    -- 【执行部分】编写具体的 SQL 和业务逻辑
    SELECT count(*) INTO v_count FROM 表名 WHERE 条件;
    
    IF v_count > 0 THEN
        -- 业务逻辑...
        参数2 := '成功'; -- 给输出参数赋值
    ELSE
        参数2 := '失败';
    END IF;

EXCEPTION
    -- 【异常处理部分】捕获并处理错误
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('未找到数据');
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('发生错误: ' || SQLERRM);
END 过程名;

2. 三种参数模式

模式 关键字 说明 使用场景
输入 IN 默认模式。调用时传入值,过程内只读。 查询条件、配置值。
输出 OUT 调用时需传入变量接收返回值,过程内可赋值。 返回统计结果、状态码、生成的主键ID。
输入输出 IN OUT 传入初始值,过程处理后修改该值并返回。 累加计算、字符串拼接处理。

3. 实战示例:用户信息处理

假设有一个表 USERS (ID, NAME, AGE, CITY)。我们要写一个存储过程:

  1. 根据 ID 查询用户。
  2. 如果用户年龄大于 18 岁且城市包含"市",则去掉城市后缀(类似你之前的 JS 逻辑)。
  3. 返回处理后的城市和状态消息。
sql 复制代码
CREATE OR REPLACE PROCEDURE PROC_UPDATE_USER_CITY (
    p_user_id   IN  NUMBER,           -- 输入:用户ID
    p_city_out  OUT VARCHAR2,         -- 输出:处理后的城市
    p_msg       OUT VARCHAR2          -- 输出:执行消息
) IS
    v_age       NUMBER;
    v_city      VARCHAR2(100);
    v_name      VARCHAR2(100);
BEGIN
    -- 1. 查询数据
    SELECT age, city, name 
    INTO v_age, v_city, v_name
    FROM USERS 
    WHERE id = p_user_id;

    -- 2. 业务逻辑判断
    IF v_age > 18 THEN
        -- 模拟去除城市后缀逻辑
        IF INSTR(v_city, '市') > 0 AND v_city NOT LIKE '%自治州%' THEN
            v_city := REPLACE(v_city, '市', '');
        END IF;
        
        p_msg := '用户 ' || v_name || ' 处理成功,新城市为:' || v_city;
    ELSE
        p_msg := '用户未成年,不处理城市信息。';
    END IF;

    -- 3. 赋值给输出参数
    p_city_out := v_city;

EXCEPTION
    WHEN NO_DATA_FOUND THEN
        p_msg := '错误:未找到 ID 为 ' || p_user_id || ' 的用户';
        p_city_out := NULL;
    WHEN OTHERS THEN
        p_msg := '系统异常:' || SQLERRM;
        p_city_out := NULL;
        -- 可选:记录日志到日志表
        -- INSERT INTO error_log VALUES (SYSDATE, SQLERRM);
END PROC_UPDATE_USER_CITY;

4. 如何调用存储过程

方法 A:在 SQL Developer / PLSQL Developer 中测试
sql 复制代码
DECLARE
    v_result_city VARCHAR2(100);
    v_message     VARCHAR2(200);
BEGIN
    -- 调用过程
    PROC_UPDATE_USER_CITY(
        p_user_id   => 1001,          -- 传入具体值
        p_city_out  => v_result_city, -- 传入变量接收
        p_msg       => v_message
    );
    
    -- 打印结果
    DBMS_OUTPUT.PUT_LINE(v_message);
    DBMS_OUTPUT.PUT_LINE('处理后城市:' || v_result_city);
END;

注意:使用前需开启输出显示 SET SERVEROUTPUT ON;

方法 B:在 Java / Python / Kettle 中调用
  • Java (JDBC): 使用 CallableStatement
  • Kettle: 使用 "Call DB Procedure" 组件,选择刚才创建的过程名,映射输入输出参数即可。

5. 常用技巧与注意事项

  1. CREATE OR REPLACE :

    • 始终加上 OR REPLACE,这样如果过程已存在,会直接覆盖更新,而不会报错。
  2. 变量赋值 :

    • 使用 := 进行赋值(如 v_count := 1;)。
    • 使用 SELECT ... INTO ... 将查询结果赋给变量。
  3. 动态 SQL :

    • 如果表名或列名需要动态变化,使用 EXECUTE IMMEDIATE
    sql 复制代码
    EXECUTE IMMEDIATE 'UPDATE ' || v_table_name || ' SET status=1 WHERE id=:1' USING p_id;
  4. 事务控制 :

    • 存储过程内部通常不写 COMMITROLLBACK,除非明确设计为独立事务。最好由调用者(外部程序)决定何时提交事务,以保持灵活性。
  5. 调试 :

    • 使用 DBMS_OUTPUT.PUT_LINE('变量值:' || v_var); 打印调试信息。

6. 常见错误排查

  • ORA-06550 / PLS-00201: 标识符必须声明(检查变量名拼写,或是否有权限访问该表)。
  • ORA-01403 : 未找到数据(SELECT INTO 没查到数据,需在 EXCEPTION 中捕获 NO_DATA_FOUND)。
  • ORA-01422 : 返回多于请求的行数(SELECT INTO 查出了多行,但变量只能存一行,需改用游标 CURSOR)。

如果你需要将之前 Kettle 中的 JavaScript 清洗逻辑迁移到 Oracle 存储过程中,我可以帮你直接转换那段代码。

相关推荐
zzh0819 分钟前
MySQL主从复制读写分离笔记
数据库·mysql
APIshop11 分钟前
京东关键词搜索接口完全指南
java·开发语言·数据库
ZzzZZzzzZZZzzzz…16 分钟前
MySQL备份还原方法1----xtrabackup
linux·运维·数据库·mysql·xtrabackup·物理备份
实泽有之,无泽虚之1 小时前
ORA-12518:Oracle 监听程序无法分发客户端连接原因及解决方法
数据库·oracle
Elastic 中国社区官方博客1 小时前
组合 OpenTelemetry 参考架构
大数据·数据库·elasticsearch·搜索引擎·架构
Z_Wonderful1 小时前
在 **Next.js** 中使用 `mysql2` 连接 MySQL 数据库并查询 `xxx` 表的数据
android·数据库
FirstFrost --sy1 小时前
MySql 内外连接
android·数据库·mysql
watersink1 小时前
第16章 案例特训专题【数据库篇】
数据库
爬山算法1 小时前
MongoDB(78)什么是MongoDB的事务?
数据库·mongodb
ego.iblacat2 小时前
MySQL 高可用
数据库·mysql·adb