语句块操作
语句块是DMSQL程序的基本单元。每个语句块由关键字DECLARE、BEGIN、EXCEPTION和END划分为声明部分、执行部分和异常处理部分。其中执行部分是必须的,说明和异常处理部分可以省略。
声明部分
声明部分包含了变量和常量的数据类型和初始值,如果不需要,可以忽略。
执行部分
所有可执行语句都放在这一块,其他语句也可以放在这一块。分号分隔每一条语句,使用赋值操作符:=或SELECT INTO或FETCH INTO给变量赋值,执行部分的错误将在异常处理部分解决,在执行部分中可以嵌套语句块。
执行部分必须包括至少一条可执行语句,NULL、COMMIT、ROLLBACK都是合法的可执行语句。DDL语句不能再执行部分使用。
异常处理部分
这是可选的。
作用域问题
一个语句块便是一个作用域范围。
实例
程序
CREATE OR REPLACE PROCEDURE PRO AS
X INT := 0; --全局变量X
BEGIN
FOR I IN 1..4 LOOP
X := X+1;
PRINT CAST(X AS CHAR(10))||'全局';
/*开始一个嵌套语句块*/
DECLARE
X INT := 10; --局部变量X
BEGIN
FOR I IN 1..4 LOOP
X:=X+10;
PRINT CAST(X AS CHAR(10))||'局部';
END LOOP;
END;
/*嵌套结束*/
END LOOP;
END;
结果
SQL> CREATE OR REPLACE PROCEDURE PRO AS
2 X INT := 0; --全局变量X
3 BEGIN
4 FOR I IN 1..4 LOOP
5 X := X+1;
6 PRINT CAST(X AS CHAR(10))||'全局';
7 /*开始一个嵌套语句块*/
8 DECLARE
9 X INT := 10; --局部变量X
10 BEGIN
11 FOR I IN 1..4 LOOP
12 X:=X+10;
13 PRINT CAST(X AS CHAR(10))||'局部';
14 END LOOP;
15 END;
16 END LOOP;
17 END;
18 /
操作已执行
已用时间: 5.996(毫秒). 执行号:1834.
SQL> CALL PRO;
1 全局
20 局部
30 局部
40 局部
50 局部
2 全局
20 局部
30 局部
40 局部
50 局部
3 全局
20 局部
30 局部
40 局部
50 局部
4 全局
20 局部
30 局部
40 局部
50 局部
DMSQL 过程已成功完成
已用时间: 0.730(毫秒). 执行号:1835.
从结果可以看出,两个X的作用域是完全不同的。
游标访问
静态游标
只读,编译时就能确定使用的查询。
隐式
无需用户隐式定义,每当用户执行DML操作,DMSQL都会自动声明一个隐式游标并对其进行管理。隐式游标的名称为”SQL“,它有%FOUND、%NOTFOUND、%ISOPEN和%ROWCOUNT这四个属性。属性意义如下:
%FOUND:语句是否修改或查询到了记录。
%NOTFOUND:语句是否为呢个成功修改或查询到记录。
%ISOPEN:游标是否打开。隐式游标永远为未打开状态。
%ROWCOUNT:DML语句影响的行数。
实例
建表
DROP TABLE IF EXISTS TEST;
CREATE TABLE TEST(
C1 INT,
C2 VARCHAR(50)
);
程序
BEGIN
UPDATE TEST SET C2 = '韩梅梅' WHERE C1=1;
IF SQL%NOTFOUND THEN
PRINT '查无此人';
ELSE
PRINT '修改成功';
END IF;
END;
结果
SQL> BEGIN
2 UPDATE TEST SET C2 = '韩梅梅' WHERE C1=1;
3 IF SQL%NOTFOUND THEN
4 PRINT '查无此人';
5 ELSE
6 PRINT '修改成功';
7 END IF;
8 END;
9 /
查无此人
DMSQL 过程已成功完成
已用时间: 0.712(毫秒). 执行号:1745.
显式
显式游标指向一个查询语句执行后的结果集区域。当需要处理返回多条记录的查询时,应显式地定义游标以处理结果集的每一行。
使用显式游标的步骤:
- 定义:声明游标及其关联查询语句。
- 打开:执行。将查询结果装入工作区,游标被定位到结果集的第一行之前。
- 拨动:根据需要将游标位置移动到结果集的合适位置。
- 关闭:使用完游标后关闭,释放其占用的资源。
实例
插入测试数据
INSERT INTO TEST VALUES(1,'韩梅梅'),(2,'李华');
程序
DECLARE
A INT;
B VARCHAR(50);
CURSOR C FOR SELECT * FROM TEST; --定义游标
BEGIN
OPEN C ; --打开游标
LOOP
FETCH C INTO A,B; --拨动游标
EXIT WHEN C%NOTFOUND;
PRINT A||'--'||B;
END LOOP;
CLOSE C; --关闭游标
END;
结果
SQL> DECLARE
2 A INT;
3 B VARCHAR(50);
4 CURSOR C FOR SELECT * FROM TEST;
5 BEGIN
6 OPEN C ;
7 LOOP
8 FETCH C INTO A,B;
9 EXIT WHEN C%NOTFOUND;
10 PRINT A||'--'||B;
11 END LOOP;
12 CLOSE C;
13 END;
14 /
1--韩梅梅
2--李华
DMSQL 过程已成功完成
已用时间: 0.234(毫秒). 执行号:1794.
动态游标
与静态游标不同,动态游标在声明部分只是先声明一个游标类型的变量,并不指定其关联的查询语句,在执行部分打开游标时才指定查询语句。
实例
程序
DECLARE
A INT;
B VARCHAR(50);
C CURSOR; --声明游标
BEGIN
OPEN C FOR SELECT * FROM TEST; --定义并打开游标
LOOP
FETCH C INTO A,B; --拨动游标
EXIT WHEN C%NOTFOUND;
PRINT A||'--'||B;
END LOOP;
CLOSE C; --关闭游标
END;
结果
SQL> DECLARE
2 A INT;
3 B VARCHAR(50);
4 C CURSOR;
5 BEGIN
6 OPEN C FOR SELECT * FROM TEST;
7 LOOP
8 FETCH C INTO A,B;
9 EXIT WHEN C%NOTFOUND;
10 PRINT A||'--'||B;
11 END LOOP;
12 CLOSE C;
13 END;
14 /
1--韩梅梅
2--李华
DMSQL 过程已成功完成
已用时间: 0.350(毫秒). 执行号:1795.
游标变量
游标变量不是真正的游标对象,而是指向游标对象的一个指针,因此是一种引用类型,也可以成为引用游标。
引用游标的特点:
- 不局限于一个查询
- 可以被赋值
- 可以作为变量使用
- 可以在DMSQL的子程序中传递结果集
实例
将TEST2表中的数据合并到TEST表中
建测试数据
DROP TABLE IF EXISTS TEST2;
CREATE TABLE TEST2(C1 INT,C2 VARCHAR(50));
INSERT INTO TEST2 VALUES(5,'刘磊'),(6,'叶枫');
程序
DECLARE
CSR CURSOR; --声明游标
PROCEDURE PROC(CSR IN CURSOR) IS --定义存储过程
PERSON TEST%ROWTYPE; --定义结果集
/*子程序开始*/
BEGIN
LOOP
FETCH CSR INTO PERSON; --拨动游标,将数据放入结果集
EXIT WHEN CSR%NOTFOUND;
INSERT INTO TEST
VALUES(PERSON.C1,PERSON.C2);--将结果集中的数据插入到TEST表中
COMMIT;
END LOOP;
END;
/*子程序结束*/
BEGIN
OPEN CSR FOR SELECT * FROM TEST2; --对游标进行定义
PROC(CSR); --存储过程调用游标
CLOSE CSR; --关闭游标
END;
结果
SQL> DECLARE
2 CSR CURSOR; --声明游标
3 PROCEDURE PROC(CSR IN CURSOR) IS --定义存储过程
4 PERSON TEST%ROWTYPE; --定义结果集
5 /*子程序开始*/
6 BEGIN
7 LOOP
8 FETCH CSR INTO PERSON; --拨动游标,将数据放入结果集
9 EXIT WHEN CSR%NOTFOUND;
10 INSERT INTO TEST
11 VALUES(PERSON.C1,PERSON.C2);--将结果集中的数据插入到TEST表中
12 END LOOP;
13 END;
14 /*子程序结束*/
15 BEGIN
16 OPEN CSR FOR SELECT * FROM TEST2; --对游标进行定义
17 PROC(CSR); --存储过程调用游标
18 CLOSE CSR; --关闭游标
19 END;
20 /
DMSQL 过程已成功完成
已用时间: 0.303(毫秒). 执行号:1912.
SQL> SELECT * FROM TEST;
行号 C1 C2
---------- ----------- ------
1 3 韩梅梅
2 2 李华
3 5 刘磊
4 6 叶枫
已用时间: 6.982(毫秒). 执行号:1913.
使用游标更新和删除数据
使用游标进行数据的更新或删除时,关联的查询语句中一定要使用”FOR UPDATE“选项,它的意义在于对要修改的行上锁,以防用户在同一行上进行修改操作。
实例——更新
程序
将TEST表中C1=1的行的C1字段改为3
DECLARE
CURSOR CSR IS SELECT C2 FROM TEST WHERE C1=1 --定义游标
FOR UPDATE; --加锁
BEGIN
OPEN CSR; --打开游标
IF CSR%ISOPEN THEN --判断游标是否被打开
FETCH CSR; --拨动游标
UPDATE TEST SET C1=3 WHERE CURRENT OF CSR; --数据更新
ELSE
PRINT 'CURSOR IS NOT OPENED';
END IF;
CLOSE CSR; --关闭游标
END;
结果
SQL> DECLARE
2 CSR CURSOR; --声明游标
3 PROCEDURE PROC(CSR IN CURSOR) IS --定义存储过程
4 PERSON TEST%ROWTYPE; --定义结果集
5 /*子程序开始*/
6 BEGIN
7 LOOP
8 FETCH CSR INTO PERSON; --拨动游标,将数据放入结果集
9 EXIT WHEN CSR%NOTFOUND;
10 INSERT INTO TEST
11 VALUES(PERSON.C1,PERSON.C2);--将结果集中的数据插入到TEST表中
12 END LOOP;
13 END;
14 /*子程序结束*/
15 BEGIN
16 OPEN CSR FOR SELECT * FROM TEST2; --对游标进行定义
17 PROC(CSR); --存储过程调用游标
18 CLOSE CSR; --关闭游标
19 END;
20 /
DMSQL 过程已成功完成
已用时间: 0.303(毫秒). 执行号:1912.
SQL> SELECT * FROM TEST;
行号 C1 C2
---------- ----------- ------
1 3 韩梅梅
2 2 李华
3 5 刘磊
4 6 叶枫
已用时间: 6.982(毫秒). 执行号:1913.
实例——FOR循环
游标FOR循环自动使用FOR循环依次读取结果集中的数据。当FOR循环开始时,游标自动打开,故而不需要使用OPEN方法;每循环一次自动读取游标当前行的数据,故而不需要使用FETCH;数据遍历完毕自动推出FOR循环时,游标自动关闭,故而不需要CLOSE。
程序
BEGIN
FOR CSR IN (SELECT * FROM TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(CSR.C1||'是'||CSR.C2||'同学');
END LOOP;
END;
结果
SQL> BEGIN
2 FOR CSR IN (SELECT * FROM TEST)
3 LOOP
4 DBMS_OUTPUT.PUT_LINE(CSR.C1||'是'||CSR.C2||'同学');
5 END LOOP;
6 END;
7 /
3是韩梅梅同学
2是李华同学
DMSQL 过程已成功完成
已用时间: 36.871(毫秒). 执行号:1810.
动态SQL
前面讲的SQL语句都是静态SQL,即先编译后执行的。除此之外,DMSQL还支持动态SQL,编译时不对其进行处理,运行时才被生成并执行。
最典型的如动态传参问题:
实例
程序
CREATE OR REPLACE PROCEDURE PRO(NUM IN INT) AS
DECLARE
SQLSTR VARCHAR:='SELECT C2 FROM TEST WHERE C1=?';
BEGIN
EXECUTE IMMEDIATE SQLSTR USING NUM;
EXCEPTION
WHEN OTHERS THEN PRINT 'ERROR';
END;
结果
SQL> CREATE OR REPLACE PROCEDURE PRO(NUM IN INT) AS
2 DECLARE
3 SQLSTR VARCHAR:='SELECT C2 FROM TEST WHERE C1=?';
4 BEGIN
5 EXECUTE IMMEDIATE SQLSTR USING NUM;
6 EXCEPTION
7 WHEN OTHERS THEN PRINT 'ERROR';
8 END;
9 /
操作已执行
已用时间: 3.876(毫秒). 执行号:1830.
SQL> CALL PRO(2);
行号 C2
---------- ----
1 李华
已用时间: 0.485(毫秒). 执行号:1831.
需注意的是,语句中的问号代表动态参数,形参的个数、问号的格式与实参的个数,都要相同。且问号是按先后顺序与参数进行匹配的。