GAUSSDB-存储过程

举报
yd_294088545 发表于 2026/01/13 21:51:03 2026/01/13
【摘要】 语法格式CREATE [ OR REPLACE ] PROCEDURE procedure_name [ ( {[ argmode ] [ argname ] argtype [ { DEFAULT | := | = } expression ]}[,...]) ] [ { IMMUTABLE | STABLE | VOLATILE } | { SHIP...

语法格式

CREATE [ OR REPLACE ] PROCEDURE procedure_name
    [ ( {[ argmode ] [ argname ] argtype [ { DEFAULT | := | = } expression ]}[,...]) ]
    [
       { IMMUTABLE | STABLE | VOLATILE }
       | { SHIPPABLE | NOT SHIPPABLE }
       | {PACKAGE}
       | [ NOT ] LEAKPROOF
       | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
       | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER}
       | COST execution_cost
       | ROWS result_rows
       | SET configuration_parameter { [ TO | = ] value | FROM CURRENT }
    ][ ... ]
 { IS | AS } 
plsql_body 
/

参数详细说明

OR REPLACE
当存在同名的存储过程时,替换原来的定义。

procedure_name
创建的存储过程名字,可以带有模式名。
取值范围:字符串,要符合标识符的命名规范。

argmode
参数的模式。

须知:
VARIADIC用于声明数组类型的参数。
取值范围: IN,OUT,INOUT或VARIADIC。缺省值是IN。只有OUT模式的参数后面能跟VARIADIC。并且OUT和INOUT模式的参数不能用在RETURNS TABLE的过程定义中。

argname
参数的名字。
取值范围:字符串,要符合标识符的命名规范。

argtype
参数的数据类型。
取值范围:可用的数据类型。

说明:
argname和argmode的顺序没有严格要求,推荐按照argname、argmode、argtype的顺序使用。

IMMUTABLE、STABLE等
行为约束可选项。各参数的功能与CREATE FUNCTION类似,详细说明见5.18.17.13-CREATE FUNCTION

plsql_body
PL/SQL存储过程体。

须知:
当在存储过程体中进行创建用户等涉及用户密码相关操作时,系统表及csv日志中会记录密码的明文。因此不建议用户在存储过程体中进行涉及用户密码的相关操作。

注意事项

(1)、函数创建也适用于存储过程,更多内容请参考CREATE FUNCTION。
(2)、如果创建存储过程时参数或返回值带有精度,不进行精度检测。
(3)、创建存储过程时,存储过程定义中对表对象的操作建议都显示指定模式,否则可能会导致存储过程执行异常。
(4)、在创建存储过程时,存储过程内部通过SET语句设置current_schema和search_path无效。执行完函数search_path和current_schema与执行函数前的search_path和current_schema保持一致。
(5)、如果存储过程参数中带有出参,SELECT调用存储过程必须缺省出参,CALL调用存储过程适配Oracle,调用非重载函数时必须指定出参,对于重载的package函数,out参数可以缺省,具体信息参见CALL的示例。
(6)、存储过程指定package属性时支持重载。
(7)、在创建procedure时,不能在avg函数外面嵌套其他agg函数,或者其他系统函数。
(8)、创建存储过程后查询定义时会返回CREATE FUNCTION的定义。
(9)、存储过程可以有多个返回值,也可以没有返回值。无返回值的存储过程调用后会有空的回显。
(10)、存储过程不支持分段提交。

示例

【方法1】
create procedure insert_data(num int)
as
declare id int;
begin
	for logid in 1000000..(1000000+num-1) loop
		insert into student values(id,now());
dbe_output.print_line('id='||id); --|| 用于做字符拼接
	end loop;
end;
/

【方法2】
create or replace procedure insert_data(num int)
as 
declare i int;
id int;
begin
	id :=100000;
	for i in 1..num loop
		insert into student values(id,sysdate);
		id :=id+1;
		dbe_output.print_line('id='||id); --|| 用于做字符拼接
	end loop;
	end;
/

【方法3】
create or replace procedure insert_data(num int)
as
begin
for i in 1.. num loop
insert into student values(100000+i-1,now());
 RAISE NOTICE 'id=%',i;
end loop;
 RAISE NOTICE '插入操作完成';
end;
/

【方法4】
create or replace procedure insert_data(num int)
as
begin
for id in 100000 .. (100000 + num-1) loop
insert into student values(id,now());
 RAISE NOTICE 'id=%',id;
end loop;
 RAISE NOTICE '插入操作完成';
end;
/

【方法1】
create or replace procedure proc_dept() 
as
	declare 
	v_dept_id int;
	v_dept_name text;
	v_dept_count int;
	cursor c_dept is select id,name from dept;
begin
 open c_dept;
 loop
 	fetch c_dept into v_dept_id,v_dept_name;
 	exit when c_dept%NOTFOUND;
 	v_dept_count := (select count(*) from Teacher where dept_no=v_dept_id);
	RAISE NOTICE '% --- %', v_dept_name, v_dept_count;
 	end loop;
 close c_dept;
 end;
/
【方法2】
create or replace procedure pro_count()
as
declare
cursor C1 is select ,count(*)  from dept d,teacher t where d.id=t.dept_no group by ;
v_name varchar(50);
v_count int;
begin
open C1;loop
fetch next from C1 into v_name,v_count;
exit when C1%NOTFOUND;
raise notice '%---%',v_name,v_count;
end loop;
close C1;
end;
/

【方法3】
---创建存储过程
create or replace procedure pro_curs_1()
as 
--定义游标
declare cursor cur1 is
select d.name as dn,count(*) as pc from teacher t,department d
where t.deptno = d.id group by d.name order by pc desc;
--调用游标
begin
	for i in cur1 loop
		--使用连接操作符“ ||”替换concat函数进行字符串连接。因为concat函数生成的执行计划不能下推,导致查询性能严重劣化。
		---DBE_OUTPUT.PRINT无法换行,导致无法输出
		--DBE_OUTPUT.PRINT_LINE函数的参数必须是字符串类型(VARCHAR2)。
		--当你使用||操作符连接字符串时,所有参与连接的操作数都必须是字符串类型。如果pc是int类型,直接与字符串连接会导致类型不匹配的错误。
		DBE_OUTPUT.PRINT_LINE(i.dn||'---'||i.pc::varchar);
	end loop;
end;
/

输出teacher表salary最高的3个和最低的3个教师信息。
【方法1】
create or replace procedure proc_teacher() as 
declare 
	v_id int;
	v_name text;
	v_depname text;
	v_salary int;
	v_title text;
	cursor c_teacher is
		select
			,
			,
			dep,
			salary,
			Title
		from
			(
			select
				ID ,
				name ,
				dept_no ,
				salary ,
				Title,
				rank() over(order by salary desc) as rn_desc,
				rank() over(order by salary) as rn_asc
			from teacher) t
		inner join dept on dep = t.dept_no
		where rn_desc <= 3 or rn_asc <= 3;

begin
 open c_teacher;

loop
 	fetch c_teacher into v_id,v_name,v_depname,v_salary,v_title;

exit when c_teacher%NOTFOUND;

raise info '%,%,%,%,%',v_id,v_name,v_depname,v_salary,v_title;

end loop;

close c_teacher;
end;
/

【方法2】
create or replace procedure proc_teacher() as
declare 
	v_id int;
	v_name text;
	v_depname text;
	v_salary int;
	v_title text;
	type cursor_type is ref cursor;
	c_teacher cursor_type;

begin
 open c_teacher for
	select
		,
		,
		dep,
		salary,
		Title
	from
		(
		select
			ID ,
			name ,
			dept_no ,
			salary ,
			Title,
			rank() over(order by salary desc) as rn_desc,
			rank() over(order by salary) as rn_asc
		from teacher) t
	inner join dept on
		dep = t.dept_no
	where
		rn_desc <= 3 or rn_asc <= 3;

loop
 	fetch c_teacher into v_id,v_name,v_depname,v_salary,v_title;

exit when c_teacher%NOTFOUND;

raise info '%,%,%,%,%',v_id,v_name,v_depname,v_salary,v_title;

end loop;

close c_teacher;
end;
/

【方法3】
create or replace procedure proc_csor2()
as
declare
	v_id int;
	v_name text;
	v_dept_name text;
	v_salary int;
	v_title text;
	type my_cursor_type is ref cursor;
	csor1 my_cursor_type;
begin
	open csor1 for 'SELECT * FROM (
						SELECT , , , t.salary, t.title,
							RANK() OVER(ORDER BY t.salary DESC) AS ranking_sal_desc,
							RANK() OVER(ORDER BY t.salary ASC) AS ranking_sal_asc
						FROM Teacher t, Dept d
						WHERE t.dept_no=d.id
					) a 
					WHERE a.ranking_sal_desc<=3 OR a.ranking_sal_asc<=3';
	LOOP
		FETCH NEXT FROM csor1 INTO v_id, v_name, v_dept_name, v_salary, v_title;
		EXIT WHEN NOT FOUND;
		raise info '%,%,%,%,%',v_id,v_name,v_dept_name,v_salary,v_title;
	END LOOP;
	close csor1;
end;
/

【方法4】
create or replace procedure get_sal_detail() 
as 
declare 
var_teacher Teacher%ROWTYPE;
cursor cur is select id,name,dept_no,salary,Title from 
(
select *,
dense_rank() over(order by salary desc) rd,
dense_rank() over(order by salary asc) ra 
from  Teacher
) where rd<=3 or ra<=3;

begin
 open cur;
 loop 
 fetch cur into var_teacher;
 exit when cur%NOTFOUND;
 raise notice '%,%,%,%,%',var_teacher.id,var_teacher.name,var_teacher.dept_no,var_teacher.salary,var_teacher.Title;
 end loop;
 close cur;
end;
/

【方法5】
创建存储过程pro_curs_2,使用游标读取薪水按降序排序的前三位老师和后三位老师的信息,分别获取ID,姓名,部门名称,薪水和职称,请按以下格式打印ID-姓名-部门名称-薪水-职称
create or replace procedure pro_curs_2() as 
declare cursor curs_2 is 
	select * from ((select t.id,t.name as tname,d.name as dname,t.salary from TEACHER t,department d where t.deptno=d.id order by salary desc limit 3) 
	union all (select t.id,t.name as tname,d.name as dname,t.salary from TEACHER t,department d where t.deptno=d.id order by salary  limit 3)) order by salary desc; 
begin 
	for i in curs_2 loop
		DBE_OUTPUT.PRINT_LINE(i.id::varchar||'--'||i.tname||'--'||i.dname||'--'||i.salary::varchar);
	end loop;	
end;
/
call pro_curs_2();


编写存储过程,输入学生id返回总成绩
【方法1】
create or replace procedure id_print_score(var_id int,total_score out int ) 
as 
begin
  select sum(math+pysical+art+music) into total_score from student where student_id=var_id group by student_id;
  return total_score;
  
EXCEPTION
    WHEN NO_DATA_FOUND THEN raise EXCEPTION '没有对应id的记录';
end;
/

【方法2】
create or replace procedure gettotalscore(vid int,totalscore out int)
as
begin
 return (select sum(math+pysical+art+music) from student where student_id=vid);
end;
/ 

【方法3】
create or replace procedure pro_total_score(id int,totalscore out int)
as 
begin
	totalscore:=(select sum(math+pysical+art+music) from student where student_id=id);
end;
/


编写存储过程,输入学号和科目名称,返回对应的平均成绩
【方法1】
create or replace procedure pro_avg_score(id int,coursename varchar(20),avgscore out int)
as
begin
	case 
	when coursename='math' then 
		select avg(math) into avgscore from student where student_id=id;
	when coursename='pysical' then 
		select avg(pysical) into avgscore from student where student_id=id;
	when coursename='art' then 
		select avg(art) into avgscore from student where student_id=id;
	when coursename='music' then 
		select avg(music) into avgscore from student where student_id=id;
	else raise notice 'input error';
	end case;
end;
/

【方法2】
create or replace procedure id_km_avg(var_id int,var_km text,avg_score out decimal(10,2)) 
as 
declare var_sql text;
begin
 var_sql:='select avg('||var_km||')  from student where student_id='||var_id;
 execute var_sql into avg_score ;
 IF avg_score IS NOT NULL then return  avg_score;
 else raise exception '没有对应的记录1';
 end if;

exception 
	when no_data_found then raise exception '没有对应的记录2';
	when others then raise exception '没有对应的记录3';
end;
/

编写存储过程,对于学生每科成绩,0-59,绩点0,60-69绩点0.1,70-79绩点0.2,80-89绩点0.3,90-100绩点0.4,输入学号和科目名称,返回对应的绩点
【方法1】
CREATE OR REPLACE PROCEDURE jd_point(id int,km varchar(200),point OUT float)
AS 
BEGIN
	IF km='math' THEN
		SELECT CASE 
			WHEN math<=59 THEN '0'
			WHEN math<=69 THEN '0.1'
			WHEN math<=79 THEN '0.2'
			WHEN math<=89 THEN '0.3'
			WHEN math<=100 THEN '0.4'
			ELSE '0'
		END 
		INTO point  FROM student s WHERE s.student_id=id LIMIT 1;
	ELSEIF km='pysical' THEN
		SELECT CASE 
			WHEN pysical<=59 THEN '0'
			WHEN pysical<=69 THEN '0.1'
			WHEN pysical<=79 THEN '0.2'
			WHEN pysical<=89 THEN '0.3'
			WHEN pysical<=100 THEN '0.4'
			ELSE '0'
		END 
		INTO point  FROM student s WHERE s.student_id=id LIMIT 1;
	ELSEIF km='art' THEN
		SELECT CASE 
			WHEN art<=59 THEN '0'
			WHEN art<=69 THEN '0.1'
			WHEN art<=79 THEN '0.2'
			WHEN art<=89 THEN '0.3'
			WHEN art<=100 THEN '0.4'
			ELSE '0'
		END 
		INTO point  FROM student s WHERE s.student_id=id LIMIT 1;
	ELSEIF  km='music' THEN
		SELECT CASE 
			WHEN music<=59 THEN '0'
			WHEN music<=69 THEN '0.1'
			WHEN music<=79 THEN '0.2'
			WHEN music<=89 THEN '0.3'
			WHEN music<=100 THEN '0.4'
			ELSE '0'
		END 
		INTO point  FROM student s WHERE s.student_id=id LIMIT 1;
	END IF;
END;	
/

【方法2】
create or replace procedure print_point(var_id int,var_km text, var_point out decimal(10,2))
as
declare var_sql text;
begin
 var_sql:= 'select 
 case 
  when '||var_km||'<60 then 0
  when '||var_km||'<70 then 0.1
  when '||var_km||'<80 then 0.2  
  when '||var_km||'<90 then 0.3  	
 else 0.4 end 
from student 
where student_id='||var_id||' limit 1';

execute var_sql into var_point;

 IF var_point IS NOT NULL then return  var_point;
 else raise exception '没有对应的记录1';
 end if;

exception 
	when no_data_found then raise exception '没有对应的记录2';
	when others then raise exception '没有对应的记录3';
end;
/


要求输入编号和课程返回成绩信息(课程和 id 本身带有单引号)
create or replace procedure get_score(var_id text,var_cid text,var_score out int) 
as
begin
select score into var_score from score where id=concat('''',var_id,'''') and cid=concat('''',var_cid,'''');
end;
/

创建存储过程pro_curs_1,使用游标打印各部门总人数,按照人数降序排序,打印格式如下 :部门名称1—人数部门名称2—人数打印操作可以使用DBE_OUTPUT.PRINT(outputstr)接口
---创建存储过程
create or replace procedure pro_curs_1()
as 
--定义游标
declare cursor cur1 is
select d.name as dn,count(*) as pc from teacher t,department d
where t.deptno = d.id group by d.name order by pc desc;
--调用游标
begin
	for i in cur1 loop
		--使用连接操作符“ ||”替换concat函数进行字符串连接。因为concat函数生成的执行计划不能下推,导致查询性能严重劣化。
		---DBE_OUTPUT.PRINT无法换行,导致无法输出
		--DBE_OUTPUT.PRINT_LINE函数的参数必须是字符串类型(VARCHAR2)。
		--当你使用||操作符连接字符串时,所有参与连接的操作数都必须是字符串类型。如果pc是int类型,直接与字符串连接会导致类型不匹配的错误。
		DBE_OUTPUT.PRINT_LINE(i.dn||'---'||i.pc::varchar);
	end loop;
end;
/

select pro_curs_1();
call pro_curs_1();
--使用raise notice输出
create or replace procedure pro_curs_1()
as
declare cursor cur1 is
select d.name as dn,count(*) as pc from teacher t,department d
where t.deptno = d.id group by d.name order by pc desc;
begin
	for i in cur1 loop
		raise notice '%-%',i.dn,i.pc;   -- 可以用raise方法输出
	end loop;
end;

---简化写法,直接调用游标
BEGIN
    FOR ROW_TRANS IN select d.name as dn,count(*) as pc from teacher t,department d
where t.deptno = d.id group by d.name order by pc desc 
    LOOP 
        DBE_OUTPUT.PRINT_LINE(ROW_TRANS.dn);
    END LOOP;
END;
/




create or replace procedure pro_curs_2() as 
declare cursor curs_2 is 
	select * from ((select t.id,t.name as tname,d.name as dname,t.salary from TEACHER t,department d where t.deptno=d.id order by salary desc limit 3) 
	union all (select t.id,t.name as tname,d.name as dname,t.salary from TEACHER t,department d where t.deptno=d.id order by salary  limit 3)) order by salary desc; 
begin 

for i in curs_2 loop
	DBE_OUTPUT.PRINT_LINE(i.id::varchar||'--'||i.tname||'--'||i.dname||'--'||i.salary::varchar);
end loop;	

end;
/
call pro_curs_2();
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。