咱们来深入了解一下PL/pgSQL,开始更灵活地用它写点东西吧。
代码块
PL/pgSQL里的代码块就是这个语言的核心构件。可以说,它就是我们函数、过程和各种“魔法”的骨架。代码块负责执行逻辑、处理数据、管理错误,全都装在一个“容器”里。
PL/pgSQL的代码块结构化,主要分三部分:
DECLARE:声明变量(可选)。BEGIN ... END:主执行块,逻辑都在这里跑。EXCEPTION:错误处理(可选)。
打个比方:想象你在看菜谱。虽然菜谱开头会列材料,真正的“魔法”都发生在烹饪过程中。用PL/pgSQL的术语来说:
DECLARE—— 就是材料清单(变量)。BEGIN ... END—— 这里就是炒菜、煮饭、搅拌的地方。EXCEPTION—— 如果糊锅了怎么办的应急方案。
PL/pgSQL代码块语法
先看看代码块的整体结构,就像“骨架”一样。后面我们再加点肉(或者你喜欢的话,加点素奶酪)——也就是具体逻辑。
DO $$
DECLARE
-- 这里声明变量
student_count INT;
BEGIN
-- 这里写逻辑
SELECT COUNT(*) INTO student_count FROM students;
RAISE NOTICE '学生总数: %', student_count;
EXCEPTION
-- 这里处理错误
WHEN OTHERS THEN
RAISE NOTICE '发生了一个错误。';
END;
$$;
咱们一步步拆解下这个例子。
DECLARE—— 这里声明变量。PL/pgSQL支持PostgreSQL几乎所有数据类型,从普通的INTEGER到很酷的JSONB都行。声明变量时,写上名字、类型,想要的话还能给个初始值。
例子:
DECLARE
student_name TEXT; -- 学生名字变量
course_count INT := 0; -- 初始值设为0
is_graduated BOOLEAN; -- 布尔变量
注意,变量可以初始化(像course_count),也可以不初始化。
BEGIN ... END—— 主执行块。
这部分负责执行主要逻辑。你可以:
- 执行SQL语句(
SELECT、INSERT等)。 - 操作数据。
- 用控制结构(
IF、LOOP等)。 - 用
RAISE输出调试信息。
例子:
BEGIN
SELECT COUNT(*) INTO student_count FROM students;
IF student_count > 0 THEN
RAISE NOTICE '有学生!';
ELSE
RAISE NOTICE '没找到学生。';
END IF;
END;
EXCEPTION—— 错误处理(可选)。
如果执行过程中出错,EXCEPTION部分能让你捕获错误,做点有用的事——比如输出消息或者执行别的代码。
例子:
BEGIN
SELECT COUNT(*) INTO student_count FROM non_existing_table; -- 错误!
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE '哎呀,出错了!';
END;
实际例子:统计学生数量
现在把所有部分拼一起,来个实际点的例子。写个PL/pgSQL块,统计students表里的学生数并输出消息。
DO $$
DECLARE
total_students INT; -- 存学生数量的变量
BEGIN
-- 统计学生数量
SELECT COUNT(*) INTO total_students FROM students;
-- 输出结果消息
RAISE NOTICE '学生数量: %', total_students;
EXCEPTION
-- 处理可能的错误,比如表不存在
WHEN OTHERS THEN
RAISE NOTICE '统计学生时发生了错误。';
END;
$$;
执行这个块会在控制台输出消息。例如:学生数量: 42。
变量使用小技巧
来聊聊几个重要点:
给变量赋值。 要把数据存进变量,可以用SELECT INTO:
SELECT COUNT(*) INTO total_students FROM students;
变量初始化。 如果声明变量时没赋值,默认就是NULL。
比如:
DECLARE
my_var INT; -- 值为NULL
RECORD类型变量。 这是个万能变量类型,可以存表里的一行。例子:
DECLARE
student RECORD;
BEGIN
SELECT * INTO student FROM students WHERE id = 1;
RAISE NOTICE '学生名: %, 年龄: %', student.name, student.age;
END;
例子:统计学生的课程数
来做个实际任务:统计某个学生选了多少门课,并输出结果。
DO $$
DECLARE
student_id INT := 1; -- 学生ID
course_count INT; -- 课程数量变量
BEGIN
-- 统计课程数量
SELECT COUNT(*) INTO course_count
FROM enrollments
WHERE student_id = student_id;
-- 输出消息
RAISE NOTICE '学生ID % 选了 % 门课。', student_id, course_count;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE '处理学生ID % 时发生了错误', student_id;
END;
$$;
这个块很灵活:你可以改student_id,查不同学生的课程数。
错误和如何避免
如果你觉得PL/pgSQL让你脑袋像微波炉里的小热狗一样炸,那很正常。刚开始经常会遇到“常见”错误。举几个例子:
没声明变量。 如果你忘了用DECLARE声明变量,PL/pgSQL会报错,说变量“不存在”。
用NULL做判断。 变量声明了但没赋值,默认是NULL。这可能导致奇怪的行为。比如:
IF my_var = NULL THEN -- 不会生效!
应该用IS NULL:
IF my_var IS NULL THEN
错误用法的EXCEPTION块。 有时候程序员捕获了所有错误(WHEN OTHERS),但啥也不做。这会把真正的问题藏起来。最好输出错误消息:
RAISE NOTICE '错误: %', SQLERRM;
GO TO FULL VERSION