PostgreSQL的函数及存储过程的基本使用

本文深入解析PostgreSQL中的存储过程与函数,包括它们的结构、变量使用、流程控制语句等内容,同时提供丰富的实例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  新人刚接触PostgreSQL数据库,在这里总结了一下存储过程中我用到了的基础知识,常常温习。

postgre数据库安装、卸载、重新安装以及pgAdmin的基本使用详见 上一篇


零、存储过程与函数的异同

  • 函数通常用于对一个或多个输入参数进行操作,主要目的是返回一个结果值;而存储过程通常包含一系列的SQL语句或其他代码块,主要目的是执行一系列的操作。
  • 函数可以被用于查询中的SELECT语句中的列表达式的一部分;而存储过程通常在PL/pgSQL代码块中运行,不能作为查询的一部分。
  • 函数可以在SELECT、UPDATE、DELETE等SQL语句中被使用;而存储过程不能直接被用于SQL语句中。
  • 函数可以有返回值;而存储过程通常没有明确的返回值,若一定需要返回值则需要使用OUT关键字。
  • 分支选择、循环等流程语句的使用方法是一致的。

一、编码结构

1.函数的结构

例: 一个求长方形面积的函数

create or replace function area_of_rectangle(lenth integer,height integer)
returns integer as
$$
declare
	area integer := 0;
begin
	area := lenth * height;
	return area;
end
$$
language 'plpgsql';

说明:

  • 第一行 用于声明函数名及需要的参数。需要注意参数格式:(变量名1 变量类型 , 变量名2 变量类型,…)
  • 第二行 声明返回值的类型。注意这里是returns,有“s”!!!
  • 第三行 两个美元符中间可以填入符合命名规则的任意字符,如$body$、$aaaa$。但是下方的美元符必须与这里的保持一致。
  • 第四行 declare表示声明变量,可以声明多个变量。
  • 第五行 声明了一个integer类型的变量并赋了初始值。
  • 第六行 begin表示语句开始
  • 第七行 计算长方形的面积
  • 第八行 将值返回
  • 第九行 end表示语句结束
  • 第十一行 声明该存储过程使用的语言。有时遇到编译报错可能是这里写成了’sql’。

调用存储过程:

select area_of_rectangle(5,9);

结果截图:
在这里插入图片描述

2.存储过程的结构

例: 一个求长方体体积的存储过程。(这个存储过程的内容毫无意义,它更适合定义为函数。这里只是用它来说明存储过程的结构,并且可以自行对比与函数的异同)

CREATE PROCEDURE volume_of_cuboid(lenth integer,width integer,height integer, OUT volume integer)
LANGUAGE plpgsql AS
$$
DECLARE
	area integer := 0;
BEGIN
    area := lenth * width;
    volume := area * height;
END;
$$

说明:

  • 第一行 用于声明存储过程的名称及需要的入参、出参。需要注意参数格式:(变量名1 变量类型 , 变量名2 变量类型,…)。并且需要用OUT关键字来标记出参,如果自定义的存储过程不需要出参则不定义即可。
  • 第二行 声明该存储过程使用的语言
  • 第三行 两个美元符中间可以填入符合命名规则的任意字符,如$body$、$aaaa$。但是下方的美元符必须与这里的保持一致。
  • 第四行 declare表示声明变量,可以声明多个变量。
  • 第五行 声明了一个integer类型的变量“面积”并赋了初始值0。
  • 第六行 begin表示语句开始
  • 第七行 计算长方体底面的面积
  • 第八行 计算长方体的体积
  • 第九行 end表示语句结束

调用存储过程:

CALL volume_of_cuboid(10, 20, 30 total);
-- 或
SELECT * FROM volume_of_cuboid(10, 20, 30);

二、变量使用

1.变量类型

存储过程中,对变量赋值需要两个值类型一致,如经常碰到bigint类型值赋值到integer变量中,导致运行报错。我用过的类型:

类型说明备注
character varying(n)变长的字符串类型在存储过程中不常用
text不限长度的字符串类型字符串类型用这个简单方便快捷
integer4字节整型
bigint8字节整形count(*)函数的查询值属于此类型
numeric(m,n)精确的小数类型
date日期类型
time时间类型
record记录类型若存储过程需要返回多行多列记录,可以用这个

更多详细变量类型可参考菜鸟教程学习:
https://www.runoob.com/postgresql/postgresql-data-type.html

2.record变量

  record类型变量是“记录类型”的变量,用于存储多行多列的值。
  按官方文档的说明,record类型的变量并不是真正的变量,该类型变量在第一次赋值前,它有多少列、每一列是什么类型都是不确定的。在第一次赋值后,该变量就根据值自动确定列的数量和各列的类型。

3.赋值

静态赋值:

student_name := '张静';

动态赋值:

select name into student_name from class where stu_No = 1;
--或者
execute 'select name from class where stu_No = 1' into student_name;

注意 “:=”“into” 是关键。


三、基本流程语句

1.分支选择

if语句:

IF ... THEN ... END IF;
IF ... THEN ... ELSE ... END IF;
IF ... THEN ... ELSE ... THEN ... ELSE ... END IF;
--例:
if student_name = '张静' then
	RAISE NOTICE '我是张静';
else if student_name like '%李%' then
	RAISE NOTICE '我姓李';
else
	RAISE NOTICE '我不是张静,也不姓李';
end if;

case语句:

CASE ... WHEN ... THEN ... ELSE ... END CASE;
CASE WHEN ... THEN ... ELSE ... END CASE;
--例:
case student_name when '张静','晓静' then
	RAISE NOTICE '张静和晓静都是我的名称';
else 
	RAISE NOTICE '你叫错名字了';
end case;
--例:
case when student_name = '张静' or student_name = '晓静' then
	RAISE NOTICE '张静和晓静都是我的名称';
else
	RAISE NOTICE '你叫错名字了';
end case;

2.循环

简单循环 中括号为可选项

[ <<label>> ]
LOOP
    循环体语句;
    EXIT [ label ] [ WHEN 判断条件表达式 ];
END LOOP [ label ];

--例-计算1到100的和:
sum := 0;
i := 0;
loop
	i := i + 1;
	sum := sum + i;
	exit when i = 100 ;
end loop;
RAISE NOTOCE '1到100的和为:%',sum;

while循环

[ <<label>> ]
WHILE 判断条件表达式 LOOP
    循环体语句;
END LOOP [ label ];

--例 - 计算1到100的和:
sum := 0;
i := 1;
while i<=100 loop
	sum := sum + i;
	i := i + 1;
end loop
RAISE NOTOCE '1到100的和为:%',sum;

for循环

[ <<label>> ]
FOR 循环控制变量 IN [ REVERSE ] 循环范围 [ BY expression ] LOOP
    循环体语句;
END LOOP [ label ];

--计算1到100的和:
--例1 - 循环执行过程类似于:for(i=1;i<=100;i++){}
sum := 0;
for i in 1..100 loop
	sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和为:%',sum;

--例2 - 循环执行过程类似于:for(i=100;i>=1;i--){}
sum := 0;
for i in REVERSE 100..1 loop
	sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和为:%',sum;

--计算1到100之间所有奇数的和
--例3 - 循环执行过程类似于:for(i=1;i<=100;i=i+2){}
sum := 0;
for i in 1..100 by 2 loop
	sum := sum + i;
end loop;
RAISE NOTOCE '1到100的和为:%',sum;

for遍历查询的结果集

[ <<label>> ]
FOR 变量 IN 查询语句 LOOP
    循环体语句;
END LOOP [ label ];

--例 - 遍历班级中每个人的名字:
for student_name in select name from class loop
	RAISE NOTICE '姓名:%',student_name;
end loop;

四、查询并返回多条记录

---- postgreSQL使用存储过程查询并显示多行多列数据 ----
---- 参考网址:https://blog.csdn.net/wuyilun2013/article/details/42779345

create or replace function f_get_member_info(id integer)
returns setof record as --setof是关键字,暂时不清楚其作用;record是返回的数据类型,即“记录类型”数据;
$$--两个美元符必须存在,中间可以填入符合命名规则的字符(如$body$,$abc$),但必须与下方的两个美元符相统一
declare
	rec record;--定义记录类型的变量,用于存储查询的结果
begin
	--开始for循环,执行SELECT语句。注意,第一个loop后没有分号!
	for rec in EXECUTE 'SELECT id,real_name FROM a_account_all' loop
		return next rec;--将查询结果依次追加到rec变量中
	end loop;--for循环结束
	return;
end
$$
language 'plpgsql';

--调用存储过程f_get_member_info示例
-- a_account_all 为存储过程中被查询的表,id和real_name是表中的字段,也是在存储过程中被查询的字段
SELECT * FROM f_get_member_info(1568) as a_account_all(id integer,real_name character varying(50));

五、其它

1、存储过程中,使用RAISE NOTICE可以在运行时将变量输出显示,可用于查看循环执行情况等。如下语句中,单引号内为输出内容,%表示变量值,loop_count为要输出显示的变量。这种输出格式与C语言中的printf()有点像。

	RAISE NOTICE '---- 已执行 % 个账号',loop_count;

2、如果存储过程编译时,一直只提示有语法错误,没有说明咋样的错误,那么先检查语言是否为plpgsql。若语言没有错误,则仔细检查begin与end之间的语句是否正确,如嵌套选择和嵌套循环是否都有对应的END

3、record变量使用示例:

-- FUNCTION: public.test()

-- DROP FUNCTION public.test();

CREATE OR REPLACE FUNCTION public.test()
    RETURNS SETOF record 
    LANGUAGE 'plpgsql'
	
	--这三句话我也还没搞懂其含义,但加上不会报错
    COST 100
    VOLATILE 
    ROWS 1000
    
AS $BODY$
DECLARE
	temp_rec record ;--第一个记录集
	rec record ;--第二个记录集
BEGIN
	--给第一个结果集赋值
	for temp_rec in execute 'SELECT 1,2,3' loop
		return next temp_rec;
		RAISE NOTICE 'temp_rec:%',temp_rec;
	end loop;
	
	--给第二个结果集赋值
	for rec in execute 'SELECT 4,5,6' loop
		return next rec;
		RAISE NOTICE 'rec:%',rec;
	end loop;
	
	--给第二个结果集追加值
	rec := (9,8,7);
	return next rec;
	
	--将两个结果集一起返回
	return ;
END
$BODY$;

ALTER FUNCTION public.test()
    OWNER TO postgres;

调用示例:
SELECT * FROM test() as temp1(num_1 integer,num_2 integer,num_3 integer);
<think>好的,我现在需要解决用户在加载预训练模型时遇到的SafetensorError,具体是'MetadataIncompleteBuffer'错误。这个问题出现在使用Hugging Face的Transformers库的from_pretrained方法时。用户可能对Safetensors和相关的错误不太熟悉,所以我得先理解这个错误的原因,然后给出解决方案。 首先,我应该回忆一下Safetensors的相关知识。Safetensors是Hugging Face开发的一种安全且高效的文件格式,用于替代传统的PyTorch bin文件。它能够加快加载速度,并且避免反序列化时的安全风险。而MetadataIncompleteBuffer错误通常与文件头部的元数据不完整或损坏有关。可能的原因包括文件下载不完整、文件损坏,或者版本不兼容。 接下来,我需要考虑用户的具体情况。用户可能在下载模型时网络中断,导致文件不完整。或者他们使用的库版本过旧,无法正确解析Safetensors文件。还有可能模型文件本身存在问题,比如上传时损坏,或者使用了不兼容的Safetensors版本生成的文件。 针对这些可能的原因,我应该分步骤给出解决方案。首先建议用户检查文件完整性,重新下载模型文件。然后,确保所有相关库(如Transformers、Safetensors)更新到最新版本,以解决兼容性问题。如果问题依旧,可以尝试禁用Safetensors,强制使用PyTorch格式,这样虽然牺牲一些性能,但可能绕过当前的问题。此外,用户可能还需要清除缓存文件,因为旧的缓存可能导致问题。 另外,我需要考虑用户可能不知道如何执行这些步骤,比如如何检查文件哈希,或者如何更新库。因此,在回答中需要给出具体的命令行指令,例如使用`wget`重新下载,或者使用`pip install --upgrade`命令更新库。同时,如果用户禁用Safetensors,需要指导他们在from_pretrained方法中添加参数`use_safetensors=False`。 最后,应该提醒用户,如果所有方法都失败,可以联系模型维护者确认文件是否有问题,或者到社区寻求帮助。例如,Hugging Face的论坛或GitHub仓库都是寻求支持的好地方。 现在,我需要确保回答结构清晰,步骤明确,并且涵盖所有可能的原因和解决方法。同时,按照用户的要求,生成相关问题,帮助用户进一步理解Safetensors和相关错误。</think>### 解决 `SafetensorError: MetadataIncompleteBuffer` 错误 #### 问题原因分析 此错误通常发生在使用 `transformers` 库的 `from_pretrained` 方法加载 Safetensors 格式的模型时,可能由以下原因导致: 1. **模型文件损坏**:文件下载不完整或传输过程中数据丢失 2. **版本不兼容**:使用的 `safetensors` 或 `transformers` 库版本过低 3. **元数据解析失败**:Safetensors 文件头部的元数据结构不符合预期格式[^1] #### 逐步解决方案 1. **验证文件完整性** - 重新下载模型文件(建议使用断点续传工具) ```bash wget --continue https://huggingface.co/[模型路径]/resolve/main/model.safetensors ``` - 检查文件哈希值是否与模型仓库中声明的匹配 2. **升级依赖库** ```bash pip install --upgrade transformers safetensors ``` 3. **清除缓存** ```python from transformers import AutoModel model = AutoModel.from_pretrained("模型名称", force_download=True) # 强制重新下载 ``` 4. **禁用 Safetensors(临时方案)** ```python model = AutoModel.from_pretrained("模型名称", use_safetensors=False) ``` 5. **检查文件编码(开发者场景)** 若需手动检查 Safetensors 文件: ```python from safetensors import safe_open with safe_open("model.safetensors", framework="pt") as f: print(f.keys()) # 验证元数据是否可读 ``` #### 技术原理说明 Safetensors 文件结构包含: $$ \text{Header} + \text{Tensor Data} $$ 其中头部使用 JSON 格式存储张量元数据。当反序列化过程中检测到 JSON 解析失败或长度不匹配时,会触发 `MetadataIncompleteBuffer` 错误[^1]。 相关问题
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值