postgresql中存储过程正式名称为procedure,自11版本起支持create procedure语法,需用call调用且不返回值;此前仅支持function,用select调用并可返回值。

存储过程在PostgreSQL里到底叫什么?
PostgreSQL 14 之前没有真正意义上的“存储过程”(PROCEDURE),只有 FUNCTION;直到 PostgreSQL 11 才引入 CREATE PROCEDURE,但必须用 CALL 调用,且不能返回值。很多人写完发现 SELECT my_proc() 报错,就是因为混淆了函数和过程。
-
FUNCTION:用SELECT或PERFORM调用,可返回值,支持RETURN、RETURN NEXT -
PROCEDURE:只能用CALL调用,不返回值,支持事务控制(COMMIT/ROLLBACK在过程体内合法) - 两者都用
LANGUAGE plpgsql,语法高度相似,但语义和调用方式不可互换
LANGUAGE plpgsql 是必须显式写的吗?
是的,除非你改了默认配置(极不推荐)。PostgreSQL 不会自动推断 PL/pgSQL —— 它甚至不会检查你写的块是不是合法 PL/pgSQL,直到首次调用才报错。
- 漏写
LANGUAGE plpgsql会报错:ERROR: function ... does not exist(其实是解析失败,不是找不到) -
LANGUAGE sql和LANGUAGE plpgsql行为差异极大:前者不支持变量、循环、异常处理,后者才支持完整逻辑 - 别用
LANGUAGE 'plpgsql'带单引号——虽然某些旧版本容忍,但标准写法是无引号的LANGUAGE plpgsql
为什么 CREATE OR REPLACE FUNCTION 后,调用还是旧逻辑?
常见于函数签名(参数类型、个数、顺序)没变,但内部逻辑改了却没生效——本质是 PostgreSQL 的函数重载机制在起作用。
- PostgreSQL 根据「函数名 + 参数类型列表」唯一标识一个函数,不是只看函数名
- 如果原函数是
my_func(int),你改写成my_func(integer),看起来一样,但integer和int是同义词,实际类型 OID 相同,会覆盖成功 - 但如果误写成
my_func(int4)或加了个默认参数,就可能创建出新重载版本,老调用仍走旧版 - 查清当前有哪些版本:
\df+ my_func(psql 命令)或查pg_proc表
事务控制在 FUNCTION 和 PROCEDURE 中的区别
这是最容易踩坑的地方:在 FUNCTION 里写 COMMIT 或 ROLLBACK 会直接报错;而 PROCEDURE 允许,但有前提。
-
FUNCTION总是运行在外部事务上下文中,不能自行结束事务 —— 报错信息通常是:ERROR: cannot commit while a cursor is open或更直白的cannot execute COMMIT in a function -
PROCEDURE可以含COMMIT,但必须用CALL在事务块外调用;若在已有事务中CALL,则COMMIT会抛出cannot commit inside a transaction block - 想安全做分段提交?用
PROCEDURE+ 显式开启新事务:BEGIN; CALL my_proc(); COMMIT;
RAISE NOTICE 很方便调试,但上线后记得删或用配置关掉 —— 它会真实发消息到客户端,可能暴露敏感路径或中间状态。










