【DM】DMSQL程序的基本操作——包括语句块、游标和动态SQL

语句块操作

语句块是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.

需注意的是,语句中的问号代表动态参数,形参的个数、问号的格式与实参的个数,都要相同。且问号是按先后顺序与参数进行匹配的。

猜你喜欢

转载自blog.csdn.net/qq_42229092/article/details/107766328