GBase 8a 支持存储过程、自定义函数的定义和使用

GBase 8a存储过程、函数:

一.概述  

存储过程是一组可以完成特定功能的 SQL 语句集,经编译后存储在数据库 中。用户在执行存储过程时,需要指定存储过程的名称并给出参数(如果存储 过程里包含参数)。 在如下情况中,存储过程非常有用:  当多个客户端应用程序是由不同的语言编写,或者运行在不同的平台, 但需要执行同样的数据库操作。  当安全非常重要时。例如,银行对所有常用的操作都使用存储过程。 这提供了一个一致的和安全的环境,并且存储过程可以保证每一个操 作都正确的写入日志。如此设置,应用程序和用户将不能直接访问数 据表,只能执行特定的存储过程。  存储过程可以提高性能,这是因为只需要在服务器和客户端之间传递 更少的信息。负面影响是增加了数据库服务器的负担,因为在服务器 端执行更多的任务而在客户端(应用程序)则只需执行较少的任务。 这在一个或很少的数据库服务器连接有大量客户端(比如 Web 服务器) 的情况下则更明显。  存储过程允许用户在数据库服务器中使用函数库。这正是现代应用程 序语言具有的特性,例如,通过使用类来进行程序设计。这些客户端 应用程序语言特性不论是否应用于数据库端的设计,对程序员来说采 用这样的方法还是很有益处的。 GBase 8a 存储过程遵循 SQL:2003 标准。 GBase 8a SQL 参考手册 - 712 - 南大通用数据技术股份有限公司 GBase 8a 存储过程仍在不断地完善中。本章中所描述的所有语法都被有效 地支持,其局限性和扩展要求将被记录备案。 关于存储过程的异常处理方法请参见《GBase 8a 存储过程异常处理参考手册》。

二. 创建存储过程、函数

存储过程和函数是由 CREATE PROCEDURE 和 CREATE FUNCTION 语句 所创建的程序。存储过程通过 CALL 语句来调用,而且只能通过输出变量得到 返回值。函数可以像其它函数一样从语句内部来调用(通过调用函数名),并 返回一个标量值。存储程序(过程和函数)也可以调用其它存储程序(过程和 函数)。 每个存储过程或函数都与一个特定的数据库相联系: 当存储程序(过程和函数)被调用时,隐含的 USE database_name 被执行 (当存储程序(过程和函数)结束时完成),不允许在存储程序(过程和函数) 中使用 USE 语句。 用户能使用数据库名来限定存储程序(过程和函数)名。这可以用来指明 不在当前数据库中的存储程序(过程和函数)。例如,要调用一个与 gbase 数据 库相关联的存储过程 p 或函数 f,用户可以使用 CALL gbase.p()或 gbase.f()。 当一个数据库被删除了,所有与它相关的存储程序(过程和函数)也都被 删除了。 GBase 8a 允许在存储过程中使用标准的 SELECT 语句。这样,一个查询的 结果简单直接地传送到客户端。多个 SELECT 语句产生多个结果集,所以客户 端必须使用一个支持多结果集的 GBase 8a 客户端库。 要创建一个存储程序(过程和函数),必须具有 CREATE ROUTINE 权限, ALTER ROUTINE 和 EXECUTE 权限自动的授予给它的创建者。如果开启更新 日志,用户可能需要 SUPER 权限。 GBase 8a SQL 参考手册 南大通用数据技术股份有限公司 - 713 - 在默认情况下,存储程序(过程和函数)与当前的数据库相关联。要显式 的将过程与数据库联系起来,那用户创建存储程序(过程和函数)时需要将它 的名字的格式写为 database_name.sp_name。 在括号中必须要有参数列表。如果没有参数,应使用空的参数列表()。默认 参数为 IN 参数。如果要将一个参数指定为其它类型,则请在参数名前使用关键 字。 使用 RETURNS 子句(只有 FUNCTION 才能指定 RETURNS 子句)指明函 数的返回类型时,函数体中必须包含一个 RETURN 语句。 如果一个存储过程或函数对同样的输入参数得到同样的结果,则被认为它 是”确定的(” DETERMINISTIC),否则就是”非确定”的(NOT DETERMINISTIC)。 如果没有指明是 DETERMINISTIC 还是 NOT DETERMINISTIC,缺省是 NOT DETERMINISTIC。 当前 DETERMINISTIC 特性是可接受的,但并不被优化器所使用。然而, 如果更新日志被激活,这个特性将影响到 GBase 8a 是否接受过程的定义。 几个特征参数提供了程序的数据使用信息。  SQL SECURITY 参数用来指明,此程序的执行权限是赋予创建者还是 调用者。缺省的值是 DEFINER。创建者和调用者必须要有对与程序相 关的数据库的访问权。要执行存储程序(过程和函数)必须具有 EXECUTE 权限,必须具有这个权限的用户要么是定义者,要么是调用 者,这依赖于如何设置 SQL SECURITY 特征。 COMMENT 语句是 GBase 8a 的扩展,可以用来描述存储过程。可以使用 SHOW CREATE PROCEDURE 和 SHOW CREATE FUNCTION 语句来显示这些 信息。 GBase 8a 允许存储程序(过程和函数)包含 DDL 语句(比如 CREATE 和 DR返回结果集的语句不能用在函数中。这些语句包括不使用 INTO 将列值赋 给变量的 SELECT 语句,SHOW 语句和比如像 EXPLAIN 这样的语句。对于在 函数定义时就返回结果集的语句返回一个 Not allowed to return a result set from a function 错误(ER_SP_NO_RETSET_IN_FUNC)。对于在函数运行时才返回结 果集的语句,返回 PROCEDURE%s can't return a result set in the given context 错 误(ER_SP_BADSELECT)。 存储过程语法格式: CREATE PROCEDURE ([[,...] [,parameter_n]]) [characteristic ...] BEGIN <过程定义> END 函数语法格式: CREATE FUNCTION ([[,…] [,parameter_n]]) RETURNS type BEGIN <函数定义> END 参数说明如下: 、要创建的存储过程的名称。在同一数据库内, 存储过程的名称必须唯一。存储过程名称只允许 a~z、A~Z、0~9、下划线, 且不能只包含数字。 ([[,…] [,parameter_n]])定义存储过程的参数,每一个参数的 定义格式是<参数方向><参数名称><参数数据类型>,其中过程<参数方向>确定 参数是输入、输出还是输入输出,只能取 IN、OUT、INOUT 中的一个。OP)和 SQL 事务语句(比如 COMMIT)。这不是标准所需要的,只是特定的实现。<参数方向><参数名称><参数数据类型>  存储过程的<参数方向>确定参数是输入、输出还是输入输出,只能取 IN、OUT、INOUT 中的一个。函数的<参数方向>只能是输入 IN。  <参数名称>在同一个存储过程中必须唯一,只允许 a~z、A~Z、0~9、 下划线,且不能只包含数字。  <参数数据类型>指定参数的数据类型。 <过程定义>、<函数定义>是一系列的 SQL 语句的组合,其中包含一些数据 操作以完成一定的功能逻辑。 定义存储过程时,存储过程名后面的括号是必需的,即使没有任何参数, 也不能省略。 如果存储过程、函数中的<过程定义>仅包含一条 SQL 语句,则可以省略 BEGIN 和 END,否则,在定义存储过程时,必须使用 BEGIN...END 结构把相 关的 SQL 语句组织在一起形成<过程定义>。 存储过程、函数可以嵌套。 type,是 GBase 8a 支持的数据类型。 下面是一个使用 IN,OUT 参数的简单的存储过程的例子。这个例子在存储 过程定义前,使用 gbase 客户端定界符命令来改变语句定界符从“;”到“//”。 这允许在存储体中,定界符传递给服务器而不被 gbase 解释。

三. 修改存储过程、函数

语法格式: ALTER {PROCEDURE | FUNCTION} [characteristic ...] characteristic: SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string'

四.删除存储过程、函数

语法格式: DROP {PROCEDURE | FUNCTION} [IF EXISTS] 参数说明如下: 要删除的存储过程(函数)的名称。

五.调用存储过程、函数

GBase 8a 使用 CALL 语句调用存储过程。 语法格式: CALL [database_name.]proc_name([<参数列表>]) 说明: 调用存储过程时,如果存储过程有参数,则必须按照存储过程的定义中的 顺序和类型为参数赋值,同时,对于 OUT 和 INOUT 参数,必须指明 OUT 和 INOUT 关键字。 即使存储过程没有任何参数,在调用时也必须在<存储过程名称>后面加上 括号。 GBase 8a 使用 SELECT 语句调用函数。 SET @变量名 = [database_name.]func_name([<参数列表>]) GBase 8a 使用 SELECT 语句查看调用函数的执行结果。 语法格式: SELECT @变量名;

六.查看存储过程、函数的状态

查看创建或修改后的存储过程或函数的状态,可以使用如下语句: SHOW {PROCEDURE | FUNCTION} STATUS SHOW CREATE {PROCEDURE | FUNCTION} 

七. 存储过程所支持的流程结构和语句

7.1 DELIMITER 

语法格式: DELIMITER [Delimiter] 分隔符是通知客户端,已经完成输入一个 SQL 语句的字符或字符串符号, 通常使用分号“;”,但在存储过程中,因为其中包含很多语句,每一个都需要 一个分号,因此需要选择不太可能出现在语句中的符号作为分隔符,如“//”。

7.2 BEGIN...END

语法格式: [begin_label:] BEGIN [statement_list] END [end_label] 存储程序(过程和函数)可能包含多个语句,这时就使用 BEGIN ... END复合语句。 statement_list:表示一个或多个语句的列表。多个语句之间使用分号“;” 进行分隔。 复合语句可以被标记。end_label 只有在 begin_label 出现后才能使用,并且 如果两者都出现,它们必须相同。 要使用多个语句,就需要客户端能发送包含语句分隔符“;”的查询字符串。 这可在客户端通过 gbase 命令行使用分隔符更改命令来处理。更改查询结束的分 隔符“;”(比如,改为//),允许“;”用在程序体中。

7.3 DECLARE

DECLARE 语句用来定义各种程序的局部项:局部变量(参看存储过程中 的变量),条件和处理器(参看条件和处理器)以及游标(参看游标)。目前 不支持 SIGNAL 和 RESIGNAL 语句。 DECLARE 只能被用在 BEGIN ... END 复合语句之间,且必须位于其它语句 之前。 游标必须在声明处理器变量之前被声明,并且条件必须在声明游标或处理 器前声明。 语法格式一: DECLARE var_name[,...] type [DEFAULT value] 这个语句用来声明局部变量。如果要对变量提供一个默认值,则包括一个 DEFAULT 语句。这个值可以指定为一个表达式,或一个常量。如果 DEFAULT 缺少子句,初始值为 NULL。 局部变量的作用范围在它被声明的 BEGIN ... END 块之间。变量可以在嵌 套块中使用,除非在块中声明了同名的变量。

7.4 SET

语法格式: SET var_name = expr [, var_name = expr] ... 存储过程中的 SET 语句是对一般 SET 语句的扩展。引用的变量可以是在一 个存储过程或全局服务器变量中声明的。 存储过程中的 SET 语句只是已存在的 SET 语法的部分实现。这允许扩展语 法 SET a=x,b=y,...这里可以混用不同的变量类型(局部变量与全局和会话服 务器变量)。这也允许局部变量和一些对系统变量有意义的选项结合起来;在 这种情况下,选项虽被认出但被忽略掉。

7.5 SELECT ...INTO...

语法格式: SELECT col_name[,...] INTO var_name[,...] table_expr 功能: 将选出的列存储到变量中。只有单一行的结果才可以被取回。

7.6 IF

GBase 8a 的 IF 结构是一个简单的条件分支结构。 语法格式: IF <判断条件> THEN <执行体> ELSE <执行体> END IF; GBase 8a 的 IF 结构允许嵌套。

7.7 ITERATE

ITERATE 语句用于实现回到指定位置重复执行,该语句只能出现在 LOOP、 REPEAT 和 WHILE 结构中,并且必须为该语句定义要回到的位置的标签,之后 在使用该语句处指定该标签。 语法格式: ITERATE<标签名> ITERATE 语句通常被放在 IF 结构中以实现根据条件重复执行。

7.8 CASE

GBase 8a 使用 CASE 结构处理多路分支的情况,其语法格式有两种,分别 描述如下: CASE WHEN <条件> THEN <执行语句> WHEN <条件> THEN <执行语句> ... GBase 8a SQL 参考手册 - 738 - 南大通用数据技术股份有限公司 ELSE <执行语句> END CASE ; 当<条件>为真值时,<执行语句>;当<条件>为真值时,<执行语句>; 如果没有匹配的结果值,那么返回 ELSE 后的<执行语句>。 CASE <判定条件> WHEN <值> THEN <执行语句> WHEN <值> THEN <执行语句> ... ELSE <执行语句> END CASE ; 计算<判定条件>,如果<判定条件>的值等于<值>,<执行语句>;如果<判定条件>的值等于<值>,<执行语句>;如果没有相匹配的值则执行<执行>。

7.9 LOOP

LOOP 结构是 GBase 8a 中的一个简单的循环结构,用于重复执行一个或者 一组语句。这个循环结构在形式上是个死循环结构,因此在执行体中通常要包 括一个条件判断语句和 LEAVE 语句用于退出循环。 语法格式: LOOP <执行体> END LOOP ;

7.10REPEAT

REPEAT 结构是 GBase 8a 中比较常见的一种循环结构,该结构会重复执行 执行体直到满足退出条件。 语法格式: REPEAT <执行体> UNTIL<退出条件> END REPEAT ;REPEAT 结构的执行体至少会执行一次,如果不允许这样可以使用 WHILE 结构代替。

7.11WHILE

WHILE 是 GBase 8a 中另一种常见的循环结构,在满足执行条件时该结构会 重复执行执行体。 语法格式: WHILE <执行条件> DO <执行体> END WHILE ; WHILE 结构在逻辑上与 REPEAT 一致,唯一不同的是 until 结构中的执行 体至少会执行一次,而 WHILE 结构中的执行体则可能一次也不执行。

7.12LEAVE

GBase 8a 中的 LEAVE 语句用于退出循环结构,因此该语句也只能出现在 LOOP、REPEAT 和 WHILE 结构中。同样的,在使用 LEAVE 语句时必须为包 含该语句的循环结构定义标签,然后在使用该语句处指定该标签。 语法格式:

LEAVE <标签名> LEAVE 语句通常被放在 IF 结构中以实现根据条件退出循环结构。

7.13静态游标(CURSOR)

由 SELECT 语句返回的结果集通常包括一系列的记录行,但经常有一些情 况下,并不总是能够将整个结果集作为一个单元来有效地处理。这时就需要一 种机制以便每次处理一行记录,数据库中的游标就提供了这种机制。由于游标 的意义,大多数的数据库都支持游标。GBase 8a 数据库也支持游标,但游标的 定义和使用有一定的限制。 本节中描述的游标为静态游标,即在 DECLARE 时必须指定 SELECT STATEMENT 语句的结果集进行绑定;在后续操作中只能对于该结果集进行只 读、仅向前的操作。 对于动态游标的定义及使用,请参见“5.7.14 动态游标(CURSOR)”。 游标必须在声明处理器之前被声明,变量和条件必须在声明游标或处理器 之前被声明。

7.13.1 游标的定义

GBase 8a 中通过 DECLARE 声明游标,标注的主体一定是一个 SELECT 语 句。 可以在一个程序中定义多个游标,但是每个块中的游标只能有一个唯一的 名字。 SELECT 语句不能包含有 INTO 子句。 语法格式: DECLARE <游标名称> CURSOR FOR  参数说明如下: <游标名称>要创建的游标的名称,只允许 a~z、A~Z、0~9、_(下划线), 且不能只包含数字。 游标的内容,可以是任何合法的 SELECT 语句。

7.13.2 打开游标

和其它数据库中使用游标的方式一样,在使用 GBase 8a 的游标前也需要使 用 OPEN 语句打开游标。 语法格式: OPEN <游标名称>

7.13.3 从游标中取得数据

使用游标的目的是为了取得游标定义中的 SELECT 语句所返回的结果集中 的字段的值,在 GBase 8a 中,这一取值的过程也是通过 FETCH 语句实现的。 语法格式: FETCH <游标名称> INTO <局部变量> 参数说明如下: <游标名称>前面定义的游标的名称,需要从该游标中取得返回值 <局部变量>从游标中取得的值要保存在这些局部变量中,FETCH 语句中要 求局部变量的数量与游标定义语句中 SELECT 语句中的选择列表中的字段数量 相同,且数据类型也要对应相同或者可以进行自动转换。这些局部变量会在后 续的语句中进行处理。

7.13.4 关闭游标

游标在使用完成后需要关闭,否则游标所占用的服务器的资源不会被释放。 如果没有明确的关闭,游标则在声明它的复合语句结束处被关闭。 语法格式: CLOSE <游标名称>

7.13.5 静态游标使用注意事项

GBase 8a 中的游标是一种只读、仅向前的游标。游标中包含的数据是不能 在使用时被更改的,并且游标中的数据只能按照从头至尾顺序读取。 GBase 8a 中的游标需要配合处理器(handler)来使用,游标需要在处理器 的声明语句之前被声明,而且,任何游标内使用的变量都需要在游标的声明语 句之前被定义。 在使用游标处理数据时,通常会使用 LOOP、REPEAT 或者 WHILE 结构, 并在这些结构的执行体中使用 FETCH 语句来遍历游标中的数据。 在 GBase 8a 中,同一个存储过程中可声明多个游标,但有以下使用上的限 制:  多个游标不能嵌套,也不能相互交叉,最好是使用完一个再使用另外 一个。  在同一个存储过程中只能定义一个处理器,这一个处理器会作用于所 有的游标,因此,如果两个游标在流程上并列执行时会变得不甚合理。  如果使用了 LOOP、REPEAT 或者 WHILE 结构来遍历游标取得数据并 进行处理,同时如果在这些循环结构的结构体中调用了存储过程,则 被调用的存储过程中不应该再包含游标和用于遍历游标的 LOOP、 REPEAT 或者 WHILE 结构,否则可能会出现一些不可预期的结果。

7.13.6 游标示例

gbase> DELIMITER // gbase> DROP PROCEDURE IF EXISTS docursor // Query OK, 0 rows affected gbase> CREATE PROCEDURE docursor() BEGIN  DECLARE s_region VARCHAR(40); DECLARE DONE INT DEFAULT(0); DECLARE cur CURSOR FOR SELECT DISTINCT c_region FROM ssbm.customer ORDER BY c_region LIMIT 6; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur; REPEAT FETCH cur INTO s_region; IF NOT done THEN SELECT s_region; END IF; UNTIL DONE END REPEAT; CLOSE cur; END // Query OK, 0 rows affected gbase> DELIMITER ; gbase> CALL docursor(); +----------+ | s_region | +----------+ | AFRICA | +----------+ 1 row in set +----------+ | s_region | +----------+ | AMERICA | +----------+ 1 row in set +----------+ | s_region | +----------+ | ASIA | +----------+ 1 row in set +----------+ | s_region | +----------+  | EUROPE | +----------+ 1 row in set +-------------+ | s_region | +-------------+ | MIDDLE EAST | +-------------+ 1 row in set Query OK, 0 rows affected

7.14动态游标(CURSOR)

GBase 8a 支持动态游标的定义和使用。 作为静态游标的加强,在 DECLARE 时使用 REF CURSOR 声明为动态游标 后,允许在 OPEN 时可多次绑定不同 SELECT STATEMENT 语句的结果集。

7.14.1 游标的定义

语法格式: DECLARE <游标名称> REF CURSOR 参数说明如下:  DECLARE:使用DECLARE定义动态游标时,不允许指定任何SELECT 语句。  <游标名称>:要创建的游标的名称,只允许 a~z、A~Z、0~9、下划 线,且不能只包含数字。  REF CURSOR:表示该游标为动态游标。

7.14.2 打开游标

和静态游标的使用方式一样,在使用动态游标前也需要使用 OPEN 语句打 开游标。 语法格式: OPEN <游标名称> FOR  参数说明如下: :游标的内容,可以是任何合法的 SELECT 语句,也可以 是动态 SQL 语句。

7.14.3 从游标中取得数据

通过 FETCH 语句,可取得动态游标 OPEN 语句中的 SELECT 语句返回的 结果集中的字段的值。 语法格式: FETCH <游标名称> INTO <局部变量> 参数说明如下: <游标名称>通过 OPEN 打开的游标的名称。 <局部变量>从游标中取得的值要保存在这些局部变量中,FETCH 语句中要 求局部变量的数量与动态游标 OPEN 语句中的 SELECT 语句中的选择列表中的 字段数量相同,且数据类型也要对应相同或者可以进行自动转换。

7.14.4 关闭游标

游标在使用完成后需要关闭,否则游标所占用的服务器的资源不会被释放。 如果没有明确的关闭,游标则在声明它的复合语句结束处被关闭。 语法格式: CLOSE <游标名称>

7.14.5 动态游标中使用的动态 SQL 语法

7.14.5.1 预处理语句中使用的动态 SQL 语法 语法格式: PREPARE stmt_name FROM open_cur_stmt EXECUTE stmt_name [USING @var_name [, @var_name] ...] {DEALLOCATE | DROP} PREPARE stmt_name 参数说明如下: :预备语句名称。 :打开动态游标的动态 SQL 语句。 通过预处理语句,可先将动态游标 OPEN 语句进行预处理,后续通过 EXECUTE 语句进行执行。 通过动态 SQL 语句,动态游标 OPEN 语句中的 SELECT 语句可以由文本字 符串或者内容为文本字符串的用户变量表示。动态 SQL 中还可包含'?'占位符表 示未定参数,在执行 EXECUTE 语句时,使用通过 USING 传入的变量值为各个 未定参数赋值,生成真正的 SELECT 语句。

7.14.5.2 OPEN 语句中使用的动态 SQL 语法

通过动态 SQL,动态游标 OPEN 语句中的 SELECT 语句可以由文本字符串 或者内容为文本字符串的用户变量表示。 语法格式: OPEN <游标名称> FOR 参数说明如下: :打开动态游标的动态 SQL 语句。

7.14.6 动态游标使用注意事项

动态游标使用时需注意如下事项: (1)动态游标在 DECLARE 时,不允许指定任何 SELECT 语句。 (2)动态游标允许嵌套,如果在嵌套中有 OPEN 操作,必须在同一嵌套中 有 CLOSE 操作与 OPEN 操作成对出现,避免重复 OPEN 操作的错误。 (3)动态游标只能用在存储过程中。

八 存储程序(过程、函数)的限制 

函数使用限制: 不支持 DML,DDL,创建临时表。 不支持函数里面涉及 SQL 查询语句,但没有禁止。 不支持下列方式给变量赋值。 例如: DECLARE res INT DEFAULT 0; SET res=(SELECT COUNT(*) FROM t); 或:SELECT COUNT(*) INTO @res FROM t;

Guess you like

Origin blog.csdn.net/weixin_62941622/article/details/121628901