CodeGym /课程 /SQL SELF /错误处理:RAISE EXCEPTION

错误处理:RAISE EXCEPTION

SQL SELF
第 52 级, 课程 0
可用

想象一下,你写了个函数用来算学生的平均分。如果你试图除以零(比如没有成绩的时候)会发生啥?你把这样的代码放到生产环境——bug就会突然冒出来。PL/pgSQL给了我们强大的错误处理工具,让你的代码更健壮、更安全、用起来也更爽。

PL/pgSQL里的错误处理可以:

  1. 生成消息,告诉你哪里出错了。
  2. 在遇到严重错误时终止代码执行。
  3. 把问题记录下来,方便以后分析。

PL/pgSQL的主要消息级别

PL/pgSQL支持好几种消息级别,帮开发者高效定位和解决问题。主要有这些:

  • NOTICE:输出信息性消息。一般用来调试。
  • WARNING:提示有潜在问题,但不会中断程序。
  • EXCEPTION:严重错误,会中断程序(并把控制权交还给调用方)。

PL/pgSQL的消息级别

消息级别 描述
NOTICE 信息或调试消息。不会影响执行
WARNING 可能有问题的警告。就像个小提示
EXCEPTION 严重错误,会终止程序执行

RAISE语句的语法

用RAISE操作符可以生成消息和处理错误。基本语法如下:

RAISE <消息级别> '消息文本' [, 变量...];
  • <消息级别> — NOTICE、WARNING、EXCEPTION。
  • '消息文本' — 问题描述。
  • [变量...] — 可以传给消息文本的额外值。

例1:用RAISE NOTICE

有时候你得知道函数内部发生了啥。比如调试循环:

DO $$
BEGIN
    FOR i IN 1..5 LOOP
        RAISE NOTICE '当前i的值: %', i;
    END LOOP;
END
$$;

结果:控制台会输出当前i的值: 1、当前i的值: 2,一直到5。

例2:用RAISE EXCEPTION

现在假设你写了个函数,遇到某些条件就得报错退出:

DO $$
BEGIN
    IF 1 = 1 THEN
        RAISE EXCEPTION '出问题啦!';
    END IF;
END
$$;

结果:执行被中断,错误消息会显示在控制台。

在RAISE里用参数

用参数可以让消息更个性化。用%占位符就行:

例3:在RAISE里插入变量

DO $$
DECLARE
    student_name TEXT := '伊万';
    average_score NUMERIC := NULL;
BEGIN
    IF average_score IS NULL THEN
        RAISE EXCEPTION '学生 % 没有平均分!', student_name;
    END IF;
END
$$;

结果:消息学生 伊万 没有平均分!。

你看,%会被student_name变量替换,让消息更有意义。

自定义错误

错误不只是意外!有时候你得故意抛出来,防止数据出错。

例4:检查输入值

写个函数,检查输入的数字,如果是负数就报错:

CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
    IF value < 0 THEN
        RAISE EXCEPTION '数字 % 是负数!', value;
    END IF;
    RETURN '数字没问题。';
END;
$$ LANGUAGE plpgsql;

现在来测试下这个函数:

SELECT check_positive(-5);

结果:错误消息数字 -5 是负数!。

如果传正数:

SELECT check_positive(10);

结果:数字没问题。

上下文中的错误处理

你会抛错当然不错,但能根据情况处理错误就更牛了。用BEGIN ... EXCEPTION块就能做到。

错误处理结构

BEGIN
    -- 你的主代码
EXCEPTION
    WHEN 错误类型 THEN
        -- 出错时要做啥
    WHEN 另一个错误 THEN
        -- 另一个错误时的操作
    WHEN OTHERS THEN
        -- 处理所有其他错误
END;

来解释下各部分:

  • EXCEPTION — 关键字,表示错误处理块开始。
  • WHEN — 指定要处理的具体错误类型,比如unique_violation或division_by_zero。
  • OTHERS — 处理所有没被明确写出来的错误。

例5:处理除零错误

举个简单的除法函数来演示错误处理:

CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    -- 尝试做除法
    RETURN a / b;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE WARNING '试图除以零。返回NULL。';
        RETURN NULL;
END;
$$ LANGUAGE plpgsql;

测试下这个函数:

SELECT safe_divide(10, 2);  -- 预期结果: 5
SELECT safe_divide(10, 0);  -- 预期结果: NULL,控制台有警告

用RAISE时常见的坑

忘记写消息级别。 如果你没写级别,PostgreSQL会报错。

错的写法:

RAISE '没有级别的消息';

对的写法:

RAISE NOTICE '有NOTICE级别的消息';

参数不对。 用了%,记得要传够变量。

错的写法:

RAISE NOTICE '带参数的例子 %';

对的写法:

RAISE NOTICE '带参数的例子 %', '值';

用太多RAISE EXCEPTION。 乱用RAISE EXCEPTION会让重要操作被中断。要用得有分寸。

实用建议

  1. 用WHEN OTHERS要小心。 能具体写错误类型就别全用OTHERS,避免把本该特殊处理的错误都拦了。
  2. 用RAISE来调试。 千万别让错误没人管。
  3. 别忘了性能。 错误处理会有点性能损耗,尤其在大存储过程里。

只要你用对了,存储过程就会很坚挺,哪怕遇到奇葩bug也不怕。PM看到会超骄傲的!

2
任务
SQL SELF, 第 52 级, 课程 0
已锁定
处理除以零的情况
处理除以零的情况
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION