№04 存储过程§1

存储过程基础

        存储过程是存储在SQL DBS上的过程,这个过程和VB6.0中的过程很像,可以传入参数,只能返回Int型的值用来反馈执行的状态或者自己定义它的其它语义(注意:凡是可以自行转换成Int类型的值也能返回,比如在存储过程中使用 return '0000003',调用的时候发现返回的是3)。

        存储过程可以看成是一系列DB操作(DML、DDL)的集合,可以在其中使用事务……所以它可以完成复杂的逻辑,许多复杂常用而连锁的业务都是写在存储过程中的,这样做有很多优点。      

        下面的主要内容来自官网CREATE PROCEDURE,官网的教程和文档十分齐全,完全没有必要写诸如我的博客上面的这些废话。但是我看东西看着看着速度就飞快,以为自己明白了就跳过,用的时候又不明白。发现写博客能让我耐心地看这些资料,并增加动手的机会以及留下思考的时间……扯远了。

        MSSQL2008R2上用户自建存储过程分为两类:T-SQL Stored Procedure  and CLR Stored Procedure(关于它们的区别,我会另外写),此系列创建的都是T-SQL SP。


创建语法

CREATE { PROC | PROCEDURE } [schema_name.] procedure_name [ ; number ] 
    [ { @parameter [ type_schema_name. ] data_type } 
        [ VARYING ] [ = default ] [ OUT | OUTPUT ] [READONLY]
    ] [ ,...n ] 
[ WITH <procedure_option> [ ,...n ] ]
[ FOR REPLICATION ] 
AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] }
[;]

<procedure_option> ::= 
    [ ENCRYPTION ]
    [ RECOMPILE ]
    [ EXECUTE AS Clause ]


参数说明

        大写的单词是关键字,是创建语法的骨架。小写的大部分是参数,或者是标记说明。中括号表示可选,比如[schema_name.]就是说创建存储过程时,模式可写可不写。

  1. schema_name:模式名(有的地方被翻译成架构),指定存储过程属于哪个模式。
  2. procedure_name:存储过程名。系统的存储过程多以sp_开头,在创建存储过程时应当避免使用sp_前缀。使用"#"前缀可以创建局部临时存储过程,“##”前缘可以创建全局临时存储过程。临时局部存储过程只对当前创建此存储过程的连接(注意不是用户)可见,当这个连接断开时,创建的临时存储过程就会被删除;全局存储过程对所有连接可见,当最后一个连接断开,它就会被删除。
  3. :number:这个在此版本之后将会被废弃,可以不用知道它。
  4. @parameter [type_schema_name.] data_type:@符后接的是参数名,[type_schema_name.] data_type是指定参数的类型,其中[type_schema_name.] 指定类型所属的模式。[VARYING] 只用来约束游标
  5. [VARYING]:只用来约束游标,和output关键字一起使用,指定游标作为一个output型的参数。(Transact-SQL stored procedures can use the cursor data type only for OUTPUT parameters. If the cursor data type is specified for a parameter, both the VARYING and OUTPUT parameters are required. If the VARYING keyword is specified for a parameter, the data type must be cursor and the OUTPUT keyword must be specified.)
  6. [ =default ][ OUT | OUTPUT ]  [READONLY] [ ,...n ]:default是默认值,可以通过此语法为参数指示默认值,[ OUT | OUTPUT ]两个都可以,指示参数将被程序修改,此修改在过程外被体现,就像C中的传地址。[READONLY]指示参数不可被存储过程修改。[,...n]表示以上参数声明可以被重复n次,之间用","隔开。
  7. [ WITH <procedure_option> [ ,...n ] ]:存储过程选项,共有三种,在创建语法的下面已列出:
    • ENCRYPTION:SQL server 会将原本的存储过程语句加密,无法查看其定义,无法修改,但是可以执行、删除。
    • RECOMPILE:重编译。每次执行此存储过程时,SQL server都会重新编译此存储过程,再执行。
    • EXECUTE AS Clause:指定执行此存储过程的上下文。
  8. FOR REPLICATION:作为自动应答的存储过程,指定了此属性后,SP不能有参数,也不能被用户调用。
  9. AS BEGIN ... END:存储过程主体。

调用语法

        { EXEC | EXECUTE } [schema_name.]procedue_name @parameter [VARYING][ OUT| OUTPUT][,...n]

如果SP为参数指定了 OUT|OUTPUT ,那么调用时该位置的参数后一定也要加此标志,否则参数值无法传出SP外。


限制和约束

        ● 以下语句不能在存储过程中使用(BEGIN...END中,是绝对不可以):

CREATE AGGREGATE

CREATE SCHEMA

SET SHOWPLAN_TEXT

CREATE DEFAULT

CREATE or ALTER TRIGGER

SET SHOWPLAN_XML

CREATE or ALTER FUNCTION

CREATE or ALTER VIEW

USE database_name

CREATE or ALTER PROCEDURE

SET PARSEONLY

 

CREATE RULE

SET SHOWPLAN_ALL

        ●在创建存储过程中可以引用不存在的表,只是在语法上允许,这个时候还没有编译,当存储过程第一次执行的时候,才会为其中各种引用指定实际的引用,此时不存在的引用就会报错。

        ●不能指定一个函数作为存储过程的参数。


例子

这是一个表无关的存储过程,输入两个数和一个计算符,计算的结果存放在一个OUT型的参数中,用来说明创建一个简单的SP:

CREATE PROC mathMethod
(
	@num_a DECIMAL(10,2)=0,
	@operator CHAR='+',
	@num_b DECIMAL(10,2)=0,
	@num_result DECIMAL(10,2)=0 OUTPUT
)
AS
BEGIN
	SET @num_result=
	CASE @operator
		WHEN '+' THEN @num_a+@num_b
		WHEN '-' THEN @num_a-@num_b
		WHEN '*' THEN @num_a*@num_b
		WHEN '/' THEN @num_a/@num_b
		ELSE 0
	END
END

T-SQL调用

DECLARE @res DECIMAL(10,2)
EXEC mathMethod 1.2,'*',2.0,@res OUT
SELECT @res;

输出

2.40

<think>我们在OpenGauss数据库中调用存储过程并传递参数给另一个存储过程,可以通过以下几种方式实现: 1. **在存储过程中直接使用CALL语句调用另一个存储过程**:如果被调用的存储过程有参数,可以在CALL语句中传递参数。 2. **使用匿名块(PL/pgSQL块)调用存储过程**:在匿名块中,我们可以使用CALL语句调用存储过程并传递参数。 3. **在存储过程中使用动态SQL调用另一个存储过程**:如果需要动态构建调用语句,可以使用EXECUTE命令执行动态SQL。 下面我们分别给出示例: ### 1. 使用CALL语句在存储过程中调用另一个存储过程 假设我们有两个存储过程:`proc1`和`proc2`。我们想在`proc1`中调用`proc2`并传递参数。 首先,创建`proc2`,它接收两个参数: ```sql CREATE OR REPLACE PROCEDURE proc2 (param1 INT, param2 VARCHAR) AS BEGIN -- 这里写proc2的处理逻辑,例如打印参数 RAISE NOTICE '参数1: %, 参数2: %', param1, param2; END; / ``` 然后,在`proc1`中,我们可以直接使用CALL语句调用`proc2`并传递参数: ```sql CREATE OR REPLACE PROCEDURE proc1 () AS BEGIN -- 调用proc2,并传递两个参数 CALL proc2(1, 'hello'); END; / ``` ### 2. 在匿名块中调用存储过程并传参 如果你不想创建存储过程,而是临时调用,可以使用匿名块: ```sql DO $$ DECLARE param1 INT := 1; param2 VARCHAR := 'hello'; BEGIN CALL proc2(param1, param2); END; $$; ``` ### 3. 使用动态SQL调用存储过程(适用于需要动态构建调用的情况) 在存储过程中,如果需要根据条件动态调用不同的存储过程或传递不同的参数,可以使用动态SQL: ```sql CREATE OR REPLACE PROCEDURE dynamic_call (proc_name VARCHAR, param1 INT, param2 VARCHAR) AS BEGIN EXECUTE format('CALL %s(%s, %L)', proc_name, param1, param2); END; / ``` 然后调用`dynamic_call`存储过程来动态调用`proc2`: ```sql CALL dynamic_call('proc2', 1, 'hello'); ``` ### 注意事项: - 在OpenGauss中,存储过程的调用使用`CALL`语句。 - 传递参数时,参数的数量、类型和顺序必须与被调用的存储过程定义一致。 - 如果存储过程有输出参数(OUT参数),那么在调用时需要使用变量来接收输出值。例如: ```sql -- 创建有OUT参数的存储过程 CREATE OR REPLACE PROCEDURE proc_with_out (x IN INT, y OUT VARCHAR) AS BEGIN y := 'result:' || x; END; / -- 调用时,需要声明变量接收OUT参数 DO $$ DECLARE result VARCHAR; BEGIN CALL proc_with_out(10, result); RAISE NOTICE '输出结果: %', result; END; $$; ``` ### 参考引用: - 在OpenGauss中,存储过程的调用语法与PostgreSQL类似,可以使用`CALL`语句[^1]。 - 对于动态SQL的使用,OpenGauss支持使用`EXECUTE`命令执行动态构建的字符串[^3]。 §§相问题§§ 1. 如何在OpenGauss存储过程中处理异常? 2. OpenGauss存储过程支持哪些参数模式(IN, OUT, INOUT)? 3. 如何调试OpenGauss存储过程?</think>在 OpenGauss 数据库中调用存储过程并传递参数给另一个存储过程,可以通过以下方式实现: ### 方法 1:使用 CALL 语句直接调用(推荐) ```sql -- 定义参数变量 DECLARE input_param1 INT := 10; -- 输入参数示例 output_param VARCHAR; -- 输出参数示例 BEGIN -- 调用存储过程并传参 CALL target_procedure( input_param1, -- 传入第一个参数 'text_value', -- 直接传入文本参数 output_param -- 接收输出参数 ); -- 使用输出参数 RAISE NOTICE '输出结果: %', output_param; END; ``` ### 方法 2:在存储过程中嵌套调用 ```sql CREATE OR REPLACE PROCEDURE caller_procedure() AS DECLARE local_var INT := 20; result_val VARCHAR; BEGIN -- 调用目标存储过程并传递参数 CALL target_procedure(local_var, 'from_caller', result_val); -- 使用返回结果 RAISE NOTICE '接收到的结果: %', result_val; END; / ``` ### 键说明: 1. **参数传递规则**: - 输入参数:直接传递值或变量 `(param_value)` - 输出参数:使用变量接收结果 `(OUT result_var)` - 输入输出参数:`(INOUT param)` 2. **参数类型匹配**: ```sql -- 目标存储过程定义示例 CREATE OR REPLACE PROCEDURE target_procedure( input1 INT, -- 输入参数 input2 VARCHAR, -- 输入参数 OUT output1 VARCHAR -- 输出参数 ) ``` 3. **动态调用场景**: ```sql EXECUTE format('CALL %s(%s, %L)', 'target_procedure', 100, 'dynamic_param'); ``` ### 注意事项: 1. 参数数量和类型必须与目标存储过程的定义严格匹配 2. 输出参数必须使用变量接收 3. 在 PL/pgSQL 块中调用时需使用 `DECLARE-BEGIN-END` 结构 4. 支持通过 `%ROWTYPE` 传递记录类型参数(需要预先定义匹配类型) ### 实际应用示例: ```sql -- 创建目标存储过程 CREATE OR REPLACE PROCEDURE calculate_bonus( IN base_salary INT, IN performance_rating FLOAT, OUT bonus_amount INT ) AS BEGIN bonus_amount := base_salary * performance_rating; END; / -- 调用存储过程 DO $$ DECLARE salary INT := 8000; rating FLOAT := 1.5; bonus INT; BEGIN CALL calculate_bonus(salary, rating, bonus); RAISE NOTICE '奖金计算结果: %', bonus; END; $$; ``` > **提示**:对于复杂参数传递,建议使用 `%TYPE` 和 `%ROWTYPE` 保证类型一致性: > ```sql > DECLARE > emp_record employee%ROWTYPE; -- 使用表结构类型 > BEGIN > CALL process_employee(emp_record); > END; > ``` [^1]: 在命令行窗口可直接使用 `CALL proc_name()` 调用存储过程 [^3]: 游标参数传递需要特殊处理,建议封装为 `REF CURSOR` 类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值