达梦数据库存储过程的特点.docx
《达梦数据库存储过程的特点.docx》由会员分享,可在线阅读,更多相关《达梦数据库存储过程的特点.docx(29页珍藏版)》请在冰豆网上搜索。
达梦数据库存储过程的特点
达梦数据库存储过程的特点
达梦数据库允许用户使用系统提供的DMPL/SQL语言创建过程或函数,这些过程或函数象普通的过程或函数一样,有输入、输出参数和返回值,它们与表和视图等数据库对象一样被存储在数据库中,供用户随时调用。
存储过程和存储函数在功能上相当于客户端的一段SQL批处理程序,但是在许多方面有着后者无法比拟的优点,它为用户提供了一种高效率的编程手段,成为现代数据库系统的重要特征。
25亿网站后台管理系统将存储过程和存储函数统称为存储模块。
达梦数据库的存储模块机制是一种技术,而不是一种独立的工具,它是和服务器紧密结合在一起的。
可以认为这种技术是执行DMPL/SQL语言的一种机器,它可以接受任何有效的存储模块,按照语言本身所规定的语义执行,并将结果返回给客户。
达梦数据库的存储模块机制具有如下优点:
1.提供更高的生产率
(1)在设计应用时,围绕存储过程/函数设计应用,可以避免重复编码,提高生产率;
(2)在自顶向下设计应用时,不必关心实现的细节;
(3)编程方便。
2.便于维护
(1)用户的存储模块在数据库集中存放;
(2)用户可以随时查询、删除它们,而应用程序可以不作任何修改,或只做少量调整。
3.提供更好的性能
(1)存储模块在创建时被编译成伪码序列,在运行时不需要重新进行编译和优化处理,它具有更快的执行速度,可以同时被多个用户调用,并能够减少操作错误;如用sqlserver修改mssql2000的存储过程所有者为dbo,这些小地方还是有些麻烦的。
(2)存储模块在执行时数据对用户是不可见的,提高了数据库的安全性;
(3)存储模块具有更高的可靠性;
(4)存储模块是一种高效访问数据库的机制,网站后台管理模板使用存储模块可减少应用对DM的调用,降低了系统资源浪费,显著提高性能,尤其是在网络上与DM通讯的应用更显著。
2.1.4.3DM与Oracle存储过程对比表
操作
Oracle
DM
差异
基本语法
存储过程:
CREATE[ORREPLACE]PROCEDUREprocedure_name
[(argument[{IN|OUT|INOUT}]type,
...
argument[{IN|OUT|INOUT}]type)]{IS|AS}
procedure_body
其中procedure_name是要创建的过程名,argument是过程的参数名,type是关联参数的类型,procedure_body是构成该过程代码的PL/SQL块。
IN,OUT,和INOUT是参数的模式,如果没有为参数指定模式,则参数缺省的模式是IN。
存储函数:
CREATE[ORREPLACE]FUNCTIONfunction_name
[(argument[{IN|OUT|INOUT}]type,
...
argument[{IN|OUT|INOUT}]type)]
RETURNreturn_type{IS|AS}
function_body
其中function_name是函数的名称,参数argument和type的含义与过程相同,return_type是函数返回值的类型,function_body是包括函数体的PL/SQL块。
IN,OUT,和INOUT是参数的模式。
如果没有为参数指定模式,则参数缺省的模式是IN。
存储过程:
CREATE[ORREPLACE]PROCEDURE<存储过程名>
[(<参数名><参数模式><参数类型>{,<参数名><参数模式><参数类型>})]
AS|IS
[<说明部分>]
<执行部分>
[<异常处理部分>]
END;
存储函数:
CREATE[ORREPLACE]FUNCTION<存储函数名>
[(<参数名><参数模式><参数类型>{,<参数名><参数模式><参数类型>})]
RETURN<返回数据类型>
AS|IS
[<说明部分>]
<执行部分>
[<异常处理部分>]
END;
在存储函数中必须使用RETURN语句向函数的调用环境返回一个值。
存储函数不能用CALL语句调用,它只能出现在表达式中。
存储函数和存储过程很相似,它们的区别在于:
1.存储过程没有返回值,而存储函数有;
2.存储过程中可以没有返回语句,而存储函数必须通过返回语句结束;
3.存储过程的返回语句中不能带表达式,而存储函数必须带表达式;
4.存储过程不能出现在一个表达式中,而存储函数只能出现在表达式中。
无
创建存储过程
CREATE[ORREPLACE]PROCEDURE<存储过程名定义>
[(<参数名><参数模式><参数类型>[<默认值表达式>]
{,<参数名><参数模式><参数类型>[<默认值表达式>]})]
[WITHENCRYPTION]AS|IS
[<说明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END;
CREATE[ORREPLACE]PROCEDURE<存储过程名定义>
[(<参数名><参数模式><参数类型>[<默认值表达式>]
{,<参数名><参数模式><参数类型>[<默认值表达式>]})]
[WITHENCRYPTION]AS|IS
[<说明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END;
无
撤销存储过程
DROPPROCEDURE<存储过程名>;
DROPPROCEDURE<存储过程名>;
无
调用存储过程
CALL<存储过程名>[(<参数>{,<参数>})];
1.CALL<存储过程名>[(<参数>{,<参数>})];
2.EXEC<存储过程名>[(<参数>{,<参数>})];
3.<存储过程名>[(<参数>{,<参数>})];
DM支持多种调用方式
创建存储函数
CREATE[ORREPLACE]FUNCTION<存储函数名定义>
[(<参数名><参数模式><参数类型>[<默认值表达式>]
{,<参数名><参数模式><参数类型>[<默认值表达式>]})]
RETURN<返回数据类型>
[WITHENCRYPTION]AS|IS
[<说明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END;
CREATE[ORREPLACE]FUNCTION<存储函数名定义>
[(<参数名><参数模式><参数类型>[<默认值表达式>]
{,<参数名><参数模式><参数类型>[<默认值表达式>]})]
RETURN<返回数据类型>
[WITHENCRYPTION]AS|IS
[<说明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END;
无
撤销存储函数
DROPFUNCTION<存储函数名>;
DROPFUNCTION<存储函数名>;
无
调用存储函数
SELECT<存储函数名>[(<参数>{,<参数>})];
SELECT<存储函数名>[(<参数>{,<参数>})];
无
PLSQL支持的结构
1.顺序结构;
2.分支结构,包括条件、循环结构等;
3.迭代结构,包括子过程、子函数的调用。
1.顺序结构;
2.分支结构,包括条件、循环结构等;
3.迭代结构,包括子过程、子函数的调用。
无
语句块结构
DECLARE
...
BEGIN
...
EXCEPTION
...
END;
语法格式:
[{DECLARE<变量说明>;}]
BEGIN
<执行部分>
[<异常处理部分>]
END
DMPL/SQL基本的程序单元;一个语句可以当作一个整体SQL语句对待,允许嵌套,可出现在SQL语句能出现的任何地方。
无
赋值语句
variable:
=expression;
给对象赋值;
语法格式:
1.<赋值对象>:
=<值表达式>
2.SET<赋值对象>=<值表达式>
需要注意的是,使用第2种形式时,不需要冒号“:
”。
DM支持多种赋值方式
变量定义
variabledata_type
[:
=|DEFAULT]default_value;
1.在语句块的说明部分可以定义变量、游标、异常变量、子过程或子函数;
2.需要强调的一点是,一个语句块意味着一个作用域范围,也就是说,在一个语句块的说明部分定义的任何对象,其作用域就是该语句块;
3.暂不支持缺省值的定义。
ORACLE支持缺省值;
DM不支持缺省值;
返回语句
RETURN;
RETURN<结果值>;
RETURN;
RETURN<结果值>;
1.结束存储模块的运行,将控制返回给调用者;
2.如果从函数返回,同时返回函数的结果。
无
退出循环
EXIT[WHENcondition];
EXIT[WHENcondition];
1.EXIT与循环语句一起使用,用于终止循环语句的执行,将控制转移到循环语句的下一个语句;
2.可以无条件终止循环语句;
3.可以带条件终止循环语句,当检测条件满足时才执行EXIT语句。
无
IF语句
IFTHEN
[ELSIF
]
…
[ELSIF
]
…
[ELSE
]
ENDIF;
根据布尔表达式的值,进行程序的分支控制;
语法格式:
IF<条件表达式>THEN
<执行部分>;
[{ELSEIF|ELSIF<条件表达式>THEN
<执行部分>;}]
[ELSE<执行部分>;]
ENDIF;
注意:
ELSEIF与ELSIF两种写法。
DM支持两种语法标记
循环语句
1.WHILE
WHILELOOP
;
[;]...
ENDLOOP;
2.LOOP
[<
LOOP
statements
ENDLOOP[label];
2FOR
FOR循环计数器IN[REVERSE]下限..上限LOOP
要执行的语句;
ENDLOOP;
5.FOR_QUERY
FORloop_nameINLOOP
;
[;]…
ENDLOOP;
1.LOOP:
循环执行,直至EXIT语句终止;
CREATEORREPLACEPROCUDUREP2
AS
AINT;
BEGIN
A:
=0;
LOOP
IFA>10THEN
EXIT;
ELSE
A:
=A+1;
ENDIF;
ENDLOOP;
END;
2.WHILE:
循环检测执行条件,为TRUE时执行,否则退出;
CREATEORREPLACEPROCEDUREP3
AS
DECLARE
AINT;
BEGIN
A:
=10;
WHILEA>0LOOP
A:
=A-1;
ENDLOOP;
END;
3.FOR:
执行指定次数;
CREATEORREPLACEPROCEDUREP4
AS
DECLARE
AINT;
BEGIN
FORAIN1..10LOOP
PRINTA;
ENDLOOP;
END;
4.REPEAT:
重复执行,直至达到条件要求。
CREATEORREPLACEPROCEDUREP5
AS
DECLARE
AINT;
BEGIN
A:
=0;
REPEAT
A:
=A+1;
UNTILA>10;
END;
无
NULL语句
NULL;
NULL;
1.不执行任何操作;
2.只用于增强程序的可读性。
无
打印语句
dbms_output.put_line(v_out.xx);
PRINT<值表达式>;
打印调试信息,用于调试存储模块。
打印语句不同,但不影响整理逻辑性
动态语句执行
EXECUTEIMMEDIATEcommandstring
INTO…USINGIN…
OUT…;
EXECUTEIMMEDIATEcommandstring
INTO…USINGIN…
OUT…;
如下例所示:
CREATEORREPLACEPROCEDUREP8
AS
V_SQLVARCHAR(2000);
V_AINT;
V_BINT;
BEGIN
V_SQL:
=‘INSERTINTOT1(A,B)VALUES(?
?
)’;
V_A:
=10;
V_B:
=10;
EXECUTEIMMEDIATEV_SQLUSINGV_A,V_B;
END;
无
游标的使用
1.定义游标
CURSORcursor_name[(parameter[,parameter]
…)]ISselect_statement;
2.打开游标
OPENcursor_name[([parameter=>]value[,[parameter
=>]value]…)];
OPENcurso_nameFORquery_stringUSINGIN…OUT…IN
OUT;
3.使用游标获取数据
FETCHcursor_nameINTO{variable_list|
record_variable};
4.关闭游标
CLOSEcursor_name;
5.游标的属性
(1)%FOUND布尔型属性,当最近一次读记录时成功返回,则值为TRUE;
(2)%NOTFOUND布尔型属性,与%FOUND相反;
(3)%ISOPEN布尔型属性,当游标已打开时返回TRUE;
(4)%ROWCOUNT数字型属性,返回已从游标中读取的记录数。
1.游标不能作为参数传递,也不能被赋值;
2.游标的四个属性:
(1)FOUND:
拨动游标,取到数据为真,否则为假;
(2)NOTFOUND:
拨动游标,取到数据为假,否则为真;
(3)ISOPEN:
游标打开为真,否则为假;
(4)ROWCOUNT:
第一次拨动之前为0,否则为拨动游标后已经取得的数据数。
3.游标变量
与普通游标不同,游标变量可以指向不同的游标工作区,它为用户提供了更灵活的数据操作方法。
定义和打开游标变量的语法与普通游标不同。
定义游标变量:
<游标变量名>CURSOR打开游标变量:
OPEN<游标变量名>FOR<不带INTO查询表达式>或OPEN<游标变量名>FOR<表达式>[USING<绑定参数>{,<绑定参数>}]其它的游标操作与普通游标相同。
例子如下:
CREATEORREPLACEPROCEDUREcurvarAS
c1CURSOR;
venameCHAR(10);
vempnoNUMERIC(4);
vsalNUMERIC(7,2);
BEGINvsal:
=2000;
OPENc1FOR'SELECTENAME,EMPNOFROMOTHER.EMPSALARYwhereSAL>?
'USINGvsal;
LOOP
FETCHc1INTOvename,vempno;
EXITWHENc1%NOTFOUND;
PRINT'NAME='||vename||'NO='||vempno;
ENDLOOP;
CLOSEc1;
END;
本例中的OPEN语句也可写成如下等价的形式:
OPENc1FORSELECTENAME,EMPNOFROMEMPwhereSAL>vsal;
无
动态语句游标定义
TYPEname_typeISREFCURSOR;
namename_type;
暂不提供动态游标的支持。
此功能非常用功能
CASE语句
CASE[expression1]
WHENexpression2THEN
;
[;...]
[WHENexpression3THEN
;
[;]...]
...
[ELSE
;
[;]...]
ENDCASE;
暂不提供CASE语句的支持。
可以使用if语句代替。
CASE表达式
CASEWHENconditionTHEN
result
[WHEN...]
[ELSEresult]
END
暂不提供CASE表达式的支持。
可以使用if语句代替。
异常的处理
1.自定义异常声明
<异常情况>
EXCEPTION;
2.抛出自定义异常
RAISE<异常情况>;
1.异常的处理
(1)在模块正常执行的过程中,可能会出现未预料的事件,称之为异常;
(2)异常会导致执行不正确的结束,因此需要进行异常处理;
(3)DM提供了一些预定义的异常,与常见的DM错误相对应;
(4)OTHERS:
特殊的异常名,用于处理没有明确列出的异常。
2.异常变量的定义
(1)用户可以自定义异常变量;
<异常变量名>EXCEPTION[FOR<错误号>];
(2)其中,FOR子句用来为异常变量绑定错误号(SQLCODE值);
(3)异常变量类似于一般的变量,必须在块的说明部分说明,有同样的生存期和作用域;
(4)但是异常变量不能作参数传递,也不能被赋值;
(5)需要注意的是,为异常变量绑定的错误号不一定是DM返回的系统错误,但是该错误号必须是一个负整数。
3.抛出异常
(1)当异常发生时,系统会自动抛出异常;
(2)用户也可以主动抛出异常:
RAISE<异常名>;
(3)一旦异常抛出,执行将转到相应的异常处理部分。
4.异常处理器
(1)语法格式:
<异常处理部分>:
:
=EXCEPTION{<异常处理语句>;}…
<异常处理语句>:
:
=WHEN<异常名>THEN<执行部分>;
(2)OTHERS必须在最后。
5.异常处理的实例
CREATEORREPLACEPROCEDUREP6
AS
AINT;
E1EXCEPTION;
BEGIN
A:
=A/0;
RAISEE1;
EXCEPTION
WHENZERO_DIVIDETHEN
PRINT‘DIVIDEDBYZERO’;
WHENE1THEN
PRINT‘E1’;
WHENOTHERSTHEN
PRINT‘ERROR’;
END;
无
SELECTINTO赋值
SELECTselect_expressionsINTOtarget
FROM...;
EXECUTEIMMEDIATEcommandstring
INTO…USINGIN…
OUT
SELECTselect_expressionsINTOtarget
FROM...;
EXECUTEIMMEDIATEcommandstring
INTO…USINGIN…
OUT
无
GOTO语句
gotolabel_name;
只能由内部的语句块跳往外部块
设置标签
<>
可以为循环设置标签
declare
idnumber:
=1;
begin
loop
dbms_output.put_line('循环次数--'||id);
id:
=id+1;
ifid=10then
gotoa;
endif;
endloop;
<>
dbms_output.put_line('跳出循环');
end;
1.GOTO语句无条件地跳转到一个标号所在的位置。
2.标号的定义在一个语句块中必须是唯一的。
其语法如下:
GOTO<标号名>GOTO语句将控制权交给带有标号的语句或语句块。
3.为了保证GOTO语句的使用不会引起程序的混乱,达梦数据库对GOTO语句的使用有下列限制:
(1)GOTO语句不能跳入一个IF语句、循环语句或下层语句块中;
(2)GOTO语句不能从一个异常处理器跳回当前块,但是可以跳转到包含当前块的上层语句块。
无
返回查询结果集
CREATEORREPLACEPROCEDUREp_sel_result(UserTagbyte)AS
BEGIN
IF(UserTag=1)THEN
SELECT*FROMSYSTABLESWHEREID>1000;
ELSE
SELECT*FROMSYSTABLESWHEREID<1000;
ENDIF;
END;
在存储过程中如果执行了不带INTO子句的查询语句,系统将在调用结束时将该查询结果集返回给调用者。
当出现多个查询语句时,只有最后被执行的查询语句的查询结果集被返回。
下面给出一个例子:
CREATEORREPLACEPROCEDUREp_sel_result(UserTagbyte)AS
BEGIN
IF(UserTag=1)THEN
SELECT*FROMSYSTABLESWHEREID>1000;
ELSE
SELECT*FROMSYSTABLESWHEREID<1000;
ENDIF;
END;
无
数据类型引用
%TYPE和%ROWTYPE扩展了存储过程类型,方便用户使用。
1.%TYPE
在许多情况下,存储过程变量可以被用来处理存储在数据库表中的数据。
在这种情况下,变量应该拥有与表列相同的类型。
2.%ROWTYPE
在存储过程中将一个记录声明为具有相同类型的数据库行的作法也很常见。
下例子中使用的表T的结果如下:
CREATETABLET(IDINT,NAMEVARCHAR(10));INSERTINTOTVALUES(1,'达梦数据库');COMMIT;
1.%TYPE
例如表T中有个字段NAME类型为VARCHAR(20)。
对应的在存储过程中,可以声明一个变量:
DELCAREV_NAMEVARCHAR(20);但是如果T中的NAME字段定义发生了变化,比如变为VARCHAR(100)。
那么存储过程中的变量V_NAME也要做相应修改为DELCAREV_NA