达梦8-DMSQL程序设计学习笔记1-DMSQL程序简介
1、DMSQL程序简介
DMSQL程序是达梦数据库对标准SQL语言的扩展,是一种过程化SQL语言。在DMSQL程序中,包括一整套数据类型、条件结构、循环结构和异常处理结构等,DMSQL程序中可以执行SQL语句,SQL语句中也可以使用DMSQL函数。
DMSQL程序是一种技术,而不是一种独立的工具,它是和DM数据库服务器紧密结合在一起的。可以认为这种技术是执行DMSQL程序的一种机器,它可以接受任何有效的DMSQL程序,按照语言本身所规定的语义执行,并将结果返回给客户。
DMSQL程序可以分为存储模块和客户端DMSQL程序两类。
用户可以使用DMSQL程序语言创建过程或函数,称为存储过程和存储函数。这些过程或函数像普通的过程或函数一样,有输入、输出参数和返回值,它们与表和视图等数据库对象一样被存储在数据库中,供用户随时调用。存储过程和存储函数在功能上相当于客户端的一段SQL批处理程序,但是在许多方面有着后者无法比拟的优点,它为用户提供了一种高效率的编程手段,成为现代数据库系统的重要特征。通常,我们将存储过程和存储函数统称为存储模块。
客户端DMSQL程序可以实现的功能与存储模块一致,不同的是客户端DMSQL程序并不创建一个具体的数据库对象。其处理方法为DM数据库服务器在预编译阶段将客户端DMSQL程序转化为虚过程。虚过程不需要存储,创建后立即执行,当执行的语句释放时,虚过程对象也一同被释放。客户端DMSQL程序只从语法上和存储模块兼容,完成和存储模块一样的功能,是一种编程手段。
2、客户端DMSQL程序
DMSQL程序语句块块没有头部部分,直接以DECLARE或者BEGIN开始。因为这个代码块没有一个可以引用的对象 ,因此不能被其他块调用,但它可以调用包括存储过程和存储函数等在内的其他函数,客户端DMSQL程序不需要存储,创建后立即执行,执行完毕即被释放。
DMSQL程序语句块由三部分组成:声明部分、执行部分和异常处理部分。
2.1、语句块
基本语法如下:
(1)声明部分
声明部分包含了变量和常量的数据类型和初始值。这个部分由关键字 DECLARE 开始。如果不需要声明变量或常量,那么可以忽略这一部分。游标的声明也放在这一部分。
(2)执行部分
执行部分是语句块中的指令部分,由关键字 BEGIN 开始,以关键字 EXCEPTION 结束,如果 EXCEPTION 不存在,那么将以关键字 END 结束。所有的可执行语句都放在这一部分,其他的语句块也可以放在这一部分。分号分隔每一条语句,使用赋值操作符:=或 SELECT INTO 或 FETCH INTO 给变量赋值,执行部分的错误将在异常处理部分解决,在执行部分中可以使用另一个语句块,这种程序块被称为嵌套块。
所有的 SQL 数据操作语句都可以用于执行部分;执行部分使用的变量和常量必须首先在声明部分声明;执行部分必须至少包括一条可执行语句,NULL 是一条合法的可执行语句;事务控制语句 COMMIT 和 ROLLBACK 可以在执行部分使用。数据定义语言(Data Definition Language,简称 DDL)不能在执行部分中使用,DDL 语句与 EXECUTE IMMEDIATE 一起使用。
(3)异常处理部分
异常处理部分是可选的,在这一部分中处理异常或错误。
一个简单的DMSQL程序:
注意:在disql中执行时,最后必须添加斜线“/“,标志着该DMSQL已经写完,可以执行。斜线”/“所在行不存在其他代码块或者执行命令。
像上面这个示例:我打算在disql交互工具中通过DMSQL程序打印当前系统时间。
输出如下:
首先是声明一个变量,变量名称为[ mess ];并设置数据类型[ varchar ],通过select语句查询出当前系统时间,并将查询结果赋值[ into ]给变量“mess”,然后再输出结果。
这里可能会遇到一个问题,就是程序执行完成了,但是并没有输出预期的结果。这时就需要进行一些设置:
(1)在disql命令行交互工具,需要打开信息打印。命令:[ set serverout on ]。
(2)如果是达梦的管理工具,想要输出信息,需要启用DBMS_OUTPUT包。
开启命令:[ DBMS_OUTPUT.ENABLE(); ],
关闭命令:[ DBMS_OUTPUT.DISABLE(); ]。
(3)或者使用[ PRINT() ]命令来输出信息。
上述的DMSQL语句块的基本语法中,声明部分和异常处理部分是可选部分。可以省略。
最简单的匿名块:
--示例:输出信息‘HELLO WORLD’
BEGIN
dbms_output.put_line('HELLO WORLD');
END;
/
输出如下:
也可以加上声明部分、异常部分
DECLARE
mess varchar(1);
BEGIN
select SYSDATE() into mess;
dbms_output.put_line(mess);
EXCEPTION
WHEN OTHERS THEN dbms_output.put_line('出错了,什么也没有!!!!!');
END;
输出如下:
由于变量的长度过小,导致程序抛出异常。
3、存储模块
包含头部单元代码块。主要有存储过程,存储函数等。
3.1、存储过程
语法如下:
CREATE [OR REPLACE] PROCEDURE [IF NOT EXISTS] <过程声明> <AS_OR_IS> <模块体>
<过程声明> ::= <存储过程名定义> [WITH ENCRYPTION][(<参数名><参数模式><参数类型> [<默认值表达式>]
{,<参数名><参数模式><参数类型> [<默认值表达式>] })][<调用权限子句>]
<存储过程名定义> ::=[<模式名>.]<存储过程名><AS_OR_IS>::= AS | IS
<模块体> ::= [<声明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END [存储过程名]
<声明部分> ::=[DECLARE]<声明定义>{<声明定义>}
<声明定义>::=<变量声明>
|<异常变量声明>
|<游标定义>
|<子过程定义>
|<子函数定义>;
<执行部分>::=<DMSQL程序语句序列>{;<DMSQL程序语句序列>}
<DMSQL程序语句序列> ::= [<标号说明>]<DMSQL程序语句>;
<标号说明>::=<<<标号名>>>
<DMSQL程序语句>::=<SQL语句>|<控制语句>
<异常处理部分>::=EXCEPTION<异常处理语句>{;<异常处理语句>}
参数说明:
- < 存储过程名>:指明被创建的存储过程的名字
- < 模式名>:指明被创建的存储过程所属模式的名字,缺省为当前模式名
- < 参数名>:指明存储过程参数的名称
- < 参数模式>:参数模式可设置为 IN、OUT 或 IN OUT(OUT IN),缺省为 IN 类型
- < 参数类型>:指明存储过程参数的数据类型
- < 声明部分>:由变量、游标和子程序等对象的声明构成,可缺省
- < 执行部分>:由 SQL 语句和过程控制语句构成的执行代码
- < 异常处理部分>:各种异常的处理程序,存储过程执行异常时调用,可缺省
- < 调用权限子句>:指定该过程中的 SQL 语句默认的模式
DBA 或具有 CREATE PROCEDURE 权限的用户可以使用上述语法新创建一个存储过程。OR REPLACE 选项的作用是当同名的存储过程存在时,首先将其删除,再创建新的存储过程。IF NOT EXISTS 选项的作用是当同名的存储过程存在时,忽略本次存储过程创建操作。当同时指定 OR REPLACE 和 IF NOT EXISTS 选项时,按照 OR REPLACE 选项的策略执行。
WITH ENCRYPTION 为可选项,如果指定 WITH ENCRYPTION 选项,则对存储过程名之后的语句部分进行加密,防止非法用户查看其具体内容。加密后的存储过程的定义可在 SYS.SYSTEXTS 系统表中查询。
存储过程可以带有参数,这样在调用存储过程时就需指定相应的实际参数,如果没有参数,过程名后面的圆括号和参数列表就可以省略了。
可执行部分是存储过程的核心部分,由 SQL 语句和流控制语句构成。支持的 SQL 语句包括:
- 数据查询语句(SELECT)
- 数据操纵语句(INSERT、DELETE、UPDATE)
- 游标定义及操纵语句(DECLARE CURSOR、OPEN、FETCH、CLOSE)
- 事务控制语句(COMMIT、ROLLBACK)
- 动态 SQL 执行语句(EXECUTE IMMEDIATE)
##示例:输出今天日期
CREATE OR REPLACE PROCEDURE TODAY_DATE AS
DECLARE
mess varchar(100);
BEGIN
select SYSDATE() into mess;
PRINT(mess);
END;
/
##调用
CALL TODAY_DATE();
--信息输出:
3.2、存储函数
语法如下:
CREATE [OR REPLACE ] FUNCTION [IF NOT EXISTS] <函数声明> <AS_OR_IS> <模块体>
<函数声明> ::= <存储函数名定义> [WITH ENCRYPTION][FOR CALCULATE][(<参数名><参数模式><参数类型> [<默认值表达式>]{,<参数名><参数模式><参数类型>[<默认值表达式>]})]RETURN <返回数据类型> [<调用选项子句>][PIPELINED]
<存储函数名定义> ::=[<模式名>.]<存储函数名>
<调用选项子句> ::= <调用选项> {<调用选项>}
<调用选项> ::= <调用权限子句> | DETERMINISTIC
<AS_OR_IS>::= AS | IS
<模块体> ::= [<声明部分>]
BEGIN
<执行部分>
[<异常处理部分>]
END [存储函数名]
<声明部分> ::=[DECLARE]<声明定义>{<声明定义>}
<声明定义>::=<变量声明>
|<异常变量声明>
|<游标定义>
|<子过程定义>
|<子函数定义>;
<执行部分>::=<DMSQL程序语句序列>{;<DMSQL程序语句序列>}
<DMSQL程序语句序列> ::= [<标号说明>]<DMSQL程序语句>;
<标号说明>::=<<<标号名>>>
<DMSQL程序语句>::=<SQL语句>|<控制语句>
<异常处理部分>::=EXCEPTION<异常处理语句>{;<异常处理语句>}
参数说明:
- < 存储函数名>:指明被创建的存储函数的名字
- < 模式名>:指明被创建的存储函数所属模式的名字,缺省为当前模式名
- < 参数名>:指明存储函数参数的名称
- < 参数模式>:参数模式可设置为 IN、OUT 或 IN OUT(OUT IN),缺省为 IN 类型
- < 参数类型>:指明存储函数参数的数据类型
- < 返回数据类型>:指明存储函数返回值的数据类型
- < 调用权限子句>:指定该过程中的 SQL 语句默认的模式
- PIPELINED:指明函数为管道表函数
存储函数与存储过程在结构和功能上十分相似,主要的差异在于:
- 存储过程没有返回值,调用者只能通过访问 OUT 或 IN
OUT 参数来获得执行结果,而存储函数有返回值,它把执行结果直接返回给调用者; - 存储过程中可以没有返回语句,而存储函数必须通过返回语句结束;
- 不能在存储过程的返回语句中带表达式,而存储函数必须带表达式;
- 存储过程不能出现在一个表达式中,而存储函数可以出现在表达式中。
FOR CALCULATE 指定存储函数为计算函数。计算函数中不支持对表进行 INSERT、DELETE、UPDATE、SELECT、上锁、设置自增列属性;对游标 DECLARE、OPEN、FETCH、CLOSE;事务的 COMMIT、ROLLBACK、SAVEPOINT、设置事务的隔离级别和读写属性;动态 SQL 的执行 EXEC、创建 INDEX、创建子过程。对于计算函数体内的函数调用必须是系统函数或者计算函数。计算函数可以被指定为表列的缺省值。
DETERMINISTIC 指定存储函数为确定性函数。在调用其的语句中,对于相同的参数返回相同的结果。如果要将一个函数作为表达式在函数索引中使用,必须指定该函数为确定性函数。当系统遇到确定性函数,它将会试图重用之前的计算结果,而不是重新计算。在确定性函数实现中,虽然没有限制不确定元素(如随机函数等)和 SQL 语句的使用,但是不推荐使用这些可能会导致结果不确定的内容。