PL/pgSQL 函数基础
编写带参数的 PL/pgSQL 函数,使用 RETURNS TABLE、控制流(IF、LOOP、FOREACH)和异常处理
PL/pgSQL 函数基础 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。
什么是 PL/pgSQL
PostgreSQL 内置的过程式语言。在 SQL 基础上扩展了变量、控制流、异常处理以及动态调用查询的能力。用于存储过程和触发器函数。
函数骨架
一个简单的函数:
CREATE OR REPLACE FUNCTION add(a INT, b INT)
RETURNS INT AS $$
BEGIN
RETURN a + b;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
SELECT add(2, 3); -- 5变量
使用 DECLARE 声明;使用 := 或 INTO 赋值:
CREATE FUNCTION user_orders(uid BIGINT)
RETURNS INT AS $$
DECLARE
cnt INT;
BEGIN
SELECT COUNT(*) INTO cnt FROM orders WHERE user_id = uid;
RETURN cnt;
END;
$$ LANGUAGE plpgsql STABLE;控制流
IF / ELSE、FOR、WHILE、CASE:
IF cnt = 0 THEN
RAISE NOTICE 'no orders';
ELSIF cnt < 10 THEN
RAISE NOTICE 'few';
ELSE
RAISE NOTICE 'many';
END IF;
FOR i IN 1..10 LOOP
RAISE NOTICE '%', i;
END LOOP;遍历查询结果
类似游标的迭代:
CREATE FUNCTION recalc_totals() RETURNS VOID AS $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT id FROM users LOOP
UPDATE users SET
order_count = (SELECT COUNT(*) FROM orders WHERE user_id = r.id)
WHERE id = r.id;
END LOOP;
END;
$$ LANGUAGE plpgsql;RETURNS TABLE
返回结果集:
CREATE FUNCTION top_buyers(n INT)
RETURNS TABLE (user_id BIGINT, total NUMERIC) AS $$
BEGIN
RETURN QUERY
SELECT o.user_id, SUM(o.total)
FROM orders o
GROUP BY o.user_id
ORDER BY SUM(o.total) DESC
LIMIT n;
END;
$$ LANGUAGE plpgsql STABLE;
SELECT * FROM top_buyers(10);IN / OUT / INOUT 参数
返回多个值:
CREATE FUNCTION stats(uid BIGINT,
OUT total NUMERIC,
OUT cnt INT) AS $$
BEGIN
SELECT SUM(total), COUNT(*) INTO total, cnt
FROM orders WHERE user_id = uid;
END;
$$ LANGUAGE plpgsql STABLE;
SELECT * FROM stats(42); -- total | cnt异常处理
BEGIN ... EXCEPTION WHEN ... THEN:
BEGIN
INSERT INTO users (email) VALUES ($1);
EXCEPTION
WHEN unique_violation THEN
RAISE NOTICE 'email already exists';
WHEN OTHERS THEN
RAISE;
END;使用 RAISE 记录日志
级别:DEBUG、LOG、INFO、NOTICE、WARNING、EXCEPTION:
RAISE NOTICE 'processed % rows', cnt;
RAISE EXCEPTION 'bad state: %', state USING ERRCODE = 'check_violation';易变性标记
为规划器正确标记函数:
- IMMUTABLE — 相同参数始终得到相同结果(不进行输入输出);允许内联和可用于索引的调用
- STABLE — 在一次查询中,相同参数得到相同结果
- VOLATILE — 每次调用的结果可能不同(默认值;适用于 NOW()、RANDOM())
SECURITY DEFINER
以函数所有者的权限运行——请谨慎使用:
CREATE FUNCTION sensitive_op() RETURNS VOID
LANGUAGE plpgsql
SECURITY DEFINER
AS $$ ... $$;
-- Always set search_path explicitly to avoid hijacking:
ALTER FUNCTION sensitive_op() SET search_path = public, pg_temp;回顾
PL/pgSQL 使用循环、IF、异常和结构化返回扩展了 SQL。对于适合在数据附近运行的连贯多步骤逻辑,请使用它。
快速检查
对于给定相同参数始终返回相同结果,且没有副作用或输入/输出的函数,应使用哪种易变性标记?
常见问题解答
「PL/pgSQL 函数基础」课时是免费的吗?
是的 — 「PL/pgSQL 函数基础」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。
「PL/pgSQL 函数基础」这节课中我会学到什么?
编写带参数的 PL/pgSQL 函数,使用 RETURNS TABLE、控制流(IF、LOOP、FOREACH)和异常处理 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「PL/pgSQL 函数基础」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Academy 课中编写并运行代码吗?
能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 触发器剖析:BEFORE/AFTER、FOR EACH ROW
- PL/pgSQL 函数基础
- DO 块与匿名代码
- 使用触发器审计表