news 2026/4/9 18:40:17

postgresql存贮过程编写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
postgresql存贮过程编写

我来为您详细介绍 PostgreSQL 存储过程的编写方法。PostgreSQL 从 11 版本开始引入了完整的存储过程(`PROCEDURE`)支持,在此之前通常使用函数(`FUNCTION`)来实现类似功能。

一、存储过程 vs 函数

特性 函数 (FUNCTION) 存储过程 (PROCEDURE)
返回值 必须有返回值 无返回值
事务控制 不能控制事务 可以使用 `COMMIT`/`ROLLBACK`
调用方式 `SELECT func()` 或 SQL 表达式 `CALL proc()`
适用场景 计算、查询 复杂业务逻辑、批量操作

二、基础语法

1. 创建存储过程

```sql
-- 基本结构
CREATE OR REPLACE PROCEDURE 过程名(
参数名 数据类型 [IN | OUT | INOUT],
...
)
LANGUAGE plpgsql
AS $$
DECLARE
-- 声明变量
BEGIN
-- 业务逻辑
EXCEPTION
-- 异常处理
END;
$$;
```

2. 完整示例

```sql
-- 示例1:简单的用户注册过程
CREATE OR REPLACE PROCEDURE sp_user_register(
p_username VARCHAR(50),
p_email VARCHAR(100),
p_password VARCHAR(255)
)
LANGUAGE plpgsql
AS $$
BEGIN
-- 检查用户名是否已存在
IF EXISTS (SELECT 1 FROM users WHERE username = p_username) THEN
RAISE EXCEPTION '用户名已存在: %', p_username;
END IF;

-- 插入新用户
INSERT INTO users (username, email, password, created_at)
VALUES (p_username, p_email, p_password, NOW());

RAISE NOTICE '用户 % 注册成功', p_username;
END;
$$;

-- 调用方式
CALL sp_user_register('john_doe', 'john@example.com', 'hashed_password');
```

三、常用控制结构

1. 条件判断

```sql
-- IF-THEN-ELSE
IF 条件 THEN
-- 语句
ELSIF 条件 THEN
-- 语句
ELSE
-- 语句
END IF;

-- CASE 表达式
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
ELSE 默认结果
END;
```

2. 循环结构

```sql
-- LOOP 循环
LOOP
EXIT WHEN 条件; -- 退出条件
END LOOP;

-- WHILE 循环
WHILE 条件 LOOP
-- 语句
END LOOP;

-- FOR 循环(整数范围)
FOR i IN 1..10 LOOP
-- 语句
END LOOP;

-- FOR 循环(查询结果集)
FOR rec IN SELECT * FROM users LOOP
RAISE NOTICE '用户: %', rec.username;
END LOOP;

-- FOREACH(遍历数组)
FOREACH item IN ARRAY arr LOOP
-- 语句
END LOOP;
```

四、事务控制(存储过程特有)

```sql
CREATE OR REPLACE PROCEDURE sp_batch_transfer()
LANGUAGE plpgsql
AS $$
DECLARE
v_count INT := 0;
BEGIN
-- 第一批操作
INSERT INTO logs (msg) VALUES ('开始批量转账');
COMMIT; -- 提交第一批

-- 第二批操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

GET DIAGNOSTICS v_count = ROW_COUNT;

IF v_count = 0 THEN
ROLLBACK; -- 回滚
RAISE EXCEPTION '转账失败';
ELSE
COMMIT; -- 提交第二批
END IF;

EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
$$;
```

五、游标操作(处理大数据量)

```sql
CREATE OR REPLACE PROCEDURE sp_process_large_table()
LANGUAGE plpgsql
AS $$
DECLARE
cur CURSOR FOR SELECT id, name FROM large_table WHERE processed = false;
rec RECORD;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO rec;
EXIT WHEN NOT FOUND;

-- 逐行处理
UPDATE large_table
SET processed = true, updated_at = NOW()
WHERE id = rec.id;

-- 每1000条提交一次,避免长事务
IF rec.id % 1000 = 0 THEN
COMMIT;
END IF;
END LOOP;
CLOSE cur;
END;
$$;
```

六、动态 SQL

```sql
CREATE OR REPLACE PROCEDURE sp_dynamic_query(
p_table_name VARCHAR(50),
p_limit INT DEFAULT 100
)
LANGUAGE plpgsql
AS $$
DECLARE
sql_query TEXT;
rec RECORD;
BEGIN
-- 构建动态SQL(注意SQL注入风险)
sql_query := format('SELECT * FROM %I LIMIT %L', p_table_name, p_limit);

-- 执行动态查询
FOR rec IN EXECUTE sql_query LOOP
RAISE NOTICE '记录: %', rec;
END LOOP;

-- 或使用 EXECUTE ... INTO
EXECUTE 'SELECT COUNT(*) FROM ' || quote_ident(p_table_name) INTO v_count;
END;
$$;
```

> 安全提示:使用 `format()` 的 `%I`(标识符)和 `%L`(字面值)或 `quote_ident()`/`quote_literal()` 防止 SQL 注入。

七、异常处理

```sql
CREATE OR REPLACE PROCEDURE sp_safe_operation()
LANGUAGE plpgsql
AS $$
BEGIN
-- 主逻辑
INSERT INTO critical_table VALUES (...);

EXCEPTION
-- 唯一约束冲突
WHEN unique_violation THEN
RAISE NOTICE '记录已存在,跳过';

-- 外键约束冲突
WHEN foreign_key_violation THEN
RAISE EXCEPTION '关联数据不存在';

-- 检查约束冲突
WHEN check_violation THEN
RAISE EXCEPTION '数据不符合约束条件';

-- 捕获所有其他异常
WHEN OTHERS THEN
RAISE EXCEPTION '未知错误: % - %', SQLSTATE, SQLERRM;
-- 或使用 RAISE NOTICE 记录后忽略
END;
$$;
```

八、输出参数

```sql
CREATE OR REPLACE PROCEDURE sp_get_user_stats(
IN p_user_id INT,
OUT total_orders INT,
OUT total_amount NUMERIC
)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT COUNT(*), COALESCE(SUM(amount), 0)
INTO total_orders, total_amount
FROM orders
WHERE user_id = p_user_id;
END;
$$;

-- 调用
CALL sp_get_user_stats(123); -- 返回结果集
```

九、最佳实践

1. 命名规范:使用 `sp_` 前缀区分存储过程
2. 参数命名:输入参数用 `p_` 前缀,输出用 `o_`,内部变量用 `v_`
3. 错误处理:始终包含 EXCEPTION 块
4. 事务粒度:合理控制事务范围,避免长事务
5. 权限控制:使用 `SECURITY DEFINER` 或 `SECURITY INVOKER`
6. 文档注释:添加详细的注释说明

```sql
COMMENT ON PROCEDURE sp_user_register IS
'用户注册存储过程
参数:
p_username - 用户名
p_email - 邮箱
p_password - 加密后的密码
异常:
用户名已存在时抛出异常';
```

十、管理命令

```sql
-- 查看所有存储过程
SELECT * FROM pg_proc WHERE prokind = 'p';

-- 修改存储过程
ALTER PROCEDURE sp_name RENAME TO new_name;

-- 删除存储过程
DROP PROCEDURE IF EXISTS sp_name;

-- 查看存储过程源码
SELECT pg_get_functiondef('sp_name'::regprocedure);
```

需要我针对某个具体业务场景(如订单处理、数据同步、报表生成等)编写更详细的存储过程示例吗?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/3 20:39:19

双卡4090D部署GPT-OSS-20B,开箱即用的网页推理体验

双卡4090D部署GPT-OSS-20B,开箱即用的网页推理体验 你有没有试过——不用写一行代码、不配环境、不调参数,点开浏览器就能和一个20B级大模型对话?不是API调用,不是远程服务,而是真正在你手边的显卡上跑起来&#xff0…

作者头像 李华
网站建设 2026/4/8 12:14:51

Z-Image-Turbo集成ControlNet全流程详解

Z-Image-Turbo集成ControlNet全流程详解 在AI图像生成领域,“快”与“准”长期难以兼得:传统扩散模型追求质量往往牺牲速度,而轻量模型又常在结构控制、细节还原上力不从心。Z-Image-Turbo的出现打破了这一惯性——它用8步推理实现10241024高…

作者头像 李华
网站建设 2026/4/2 11:54:23

IQuest-Coder-V1-40B-Instruct部署手册:多GPU并行配置

IQuest-Coder-V1-40B-Instruct部署手册:多GPU并行配置 1. 为什么需要关注这个模型 你可能已经用过不少代码大模型,但IQuest-Coder-V1-40B-Instruct有点不一样——它不是为“写点小脚本”设计的,而是冲着真实软件工程场景去的。比如&#xf…

作者头像 李华
网站建设 2026/4/8 9:58:47

革新AI视频创作:ComfyUI-LTXVideo实战技术指南

革新AI视频创作:ComfyUI-LTXVideo实战技术指南 【免费下载链接】ComfyUI-LTXVideo LTX-Video Support for ComfyUI 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-LTXVideo 在数字内容创作的浪潮中,AI视频生成技术正经历着前所未有的…

作者头像 李华
网站建设 2026/3/30 15:17:03

如何用N_m3u8DL-RE实现高质量视频下载?2024最新全场景指南

如何用N_m3u8DL-RE实现高质量视频下载?2024最新全场景指南 【免费下载链接】N_m3u8DL-RE 跨平台、现代且功能强大的流媒体下载器,支持MPD/M3U8/ISM格式。支持英语、简体中文和繁体中文。 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8DL-…

作者头像 李华
网站建设 2026/4/5 7:46:24

springboot街道摊贩管理系统设计开发实现

街道摊贩管理系统设计开发的背景与意义 背景 城市化进程加快导致流动摊贩数量激增,传统人工管理方式效率低下,易引发占道经营、卫生安全等问题。政府需数字化手段规范管理,平衡市容秩序与民生需求。 意义 规范管理:通过信息化…

作者头像 李华