DM存储过程和函数中常用的变量、循环、游标、抛出异常
DM存储过程和函数中常用的变量、循环、游标、抛出异常
- 1 变量定义
- 1.1 定义变量
- 1.2 变量赋值
- 2 循环控制
- 2.1 LOOP
- 2.2 WHILE
- 2.3 FOR
- 2.4 REPEAT
- 2.5 FORALL
- 2.6 CONTINUE
- 3 游标
- 3.1 静态游标
- 3.1.1 隐式游标
- 3.1.2 显式游标
- 3.2 动态游标
- 3.3 游标引用
- 3.4 游标FOR循环
- 4 抛出异常
1 变量定义
变量名必须以字母或下划线、KaTeX parse error: Expected 'EOF', got '#' at position 2: 、#̲符号开头,包含数字、字母、下划…、#符号,长度不能超过128字符,并且不能与DM的DMSQL程序保留字相同,变量名与大小写是无关的。变量的数据类型可以是基本的SQL数据类型,也可以是DMSQL程序数据类型,比如一个游标、异常等。
1.1 定义变量
例如,定义一个int类型的变量,并打印出来。
SQL> DECLAREi_num INT;
BEGINPRINT i_num;
end;NULL
DMSQL 过程已成功完成
已用时间: 0.220(毫秒). 执行号:1803.
例如,定义一个有默认值的varchar类型的变量,并打印出来。
SQL> DECLAREi_var VARCHAR:='test var!!!';
BEGINPRINT i_var;
end;test var!!!
DMSQL 过程已成功完成
已用时间: 1.920(毫秒). 执行号:1804.
1.2 变量赋值
变量定义后,重新赋予新的变量参数值。
例如:对前面定义的int类型变量赋予一个新的参数值,并打印出来。
SQL> DECLAREi_num INT;
BEGINi_num := 999;PRINT i_num;
end;999
DMSQL 过程已成功完成
已用时间: 0.486(毫秒). 执行号:1805.
2 循环控制
2.1 LOOP
LOOP语句实现对一语句系列的重复执行,是循环语句的最简单形式。LOOP和ENDLOOP之间的执行部分将无限次地执行,必须借助EXIT、GOTO或RAISE语句来跳出循环。
例如,通过exit退出循环。
SQL> DECLAREI_NUM INT:=1;
BEGINLOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';IF I_NUM%3=0 THENEXIT;END IF;I_NUM = I_NUM+1;END LOOP;
END;这是第1输出!
这是第2输出!
这是第3输出!
DMSQL 过程已成功完成
已用时间: 0.618(毫秒). 执行号:1806.
例如,使用RAISE抛出异常,结束循环。
SQL> DECLAREI_NUM INT:=1;E_EXIT_LOOP EXCEPTION;
BEGINLOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';IF I_NUM%3=0 THENRAISE E_EXIT_LOOP;END IF;I_NUM = I_NUM+1;END LOOP;
EXCEPTIONWHEN E_EXIT_LOOP THENPRINT '这是LOOP 触发的RAISE异常';
END;这是第1输出!
这是第2输出!
这是第3输出!
这是LOOP 触发的RAISE异常
DMSQL 过程已成功完成
已用时间: 2.673(毫秒). 执行号:1807.
例如,使用GOTO结束循环。
SQL> DECLAREI_NUM INT:=1;
BEGINLOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';IF I_NUM%3=0 THENGOTO GOTO_POINT;END IF;I_NUM = I_NUM+1;END LOOP;<<GOTO_POINT>>PRINT '使用 GOTO 跳出循环';
END;这是第1输出!
这是第2输出!
这是第3输出!
使用 GOTO 跳出循环
DMSQL 过程已成功完成
已用时间: 2.598(毫秒). 执行号:1808.
2.2 WHILE
WHILE循环语句在每次循环开始之前,先计算条件表达式,若该条件为TRUE,执行部分被执行一次,然后控制重新回到循环顶部。若条件表达式的值为FALSE,则结束循环。当然,也可以通过EXIT语句来终止循环。
SQL> DECLAREI_NUM INT:=1;
BEGINWHILE I_NUM<3 LOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';I_NUM = I_NUM+1;END LOOP;
END;这是第1输出!
这是第2输出!
DMSQL 过程已成功完成
已用时间: 2.319(毫秒). 执行号:1809.
2.3 FOR
执行FOR语句时,首先检查下限表达式的值是否小于上限表达式的值,如果下限数值大于上限数值,则不执行循环体。否则,将下限数值赋给循环计数器(语句中使用了REVERSE关键字时,则把上限数值赋给循环计数器);然后执行循环体内的语句序列;执行完后,循环计数器值加1(如果有REVERSE关键字,则减1);检查循环计数器的值,若仍在循环范围内,则重新继续执行循环体;如此循环,直到循环计数器的值超出循环范围。同样,也可以通过EXIT语句来终止循环。
SQL> BEGINfor I_NUM in 1..3 LOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';END LOOP;
END;这是第1输出!
这是第2输出!
这是第3输出!
DMSQL 过程已成功完成
已用时间: 0.578(毫秒). 执行号:1810.
2.4 REPEAT
REPEAT语句先执行执行部分,然后判断条件表达式,若为TRUE则控制重新回到循环顶部,若为FALSE则退出循环。可以看出,REPEAT语句的执行部分至少会执行一次。
SQL> DECLAREI_NUM INT:=1;
BEGINREPEATPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';I_NUM = I_NUM+1;UNTIL I_NUM>3;
END;这是第1输出!
这是第2输出!
这是第3输出!
DMSQL 过程已成功完成
已用时间: 0.353(毫秒). 执行号:1811.
2.5 FORALL
限制较多:不能使用循环变量I,仅能循环执行1条DML。
CREATE TEMPORARY TABLE T_TEST_TMP(C VARCHAR(100));BEGINFORALL I IN 1..3INSERT INTO T_TEST_TMP SELECT '这是第1输出!';
END;SELECT * FROM T_TEST_TMP;
2.6 CONTINUE
CONTINUE语句的作用是退出当前循环,并且将语句控制转移到这次循环的下一次循环迭代或者是一个指定标签的循环的开始位置并继续执行。
DECLAREI_NUM INT:=1;
BEGIN<<flag1>> FOR I IN 1..3 LOOPPRINT '第1层循环,第'||TO_CHAR(I)||'输出!';FOR J IN 1..5 LOOPPRINT '第2层循环,第'||TO_CHAR(I_NUM)||'输出!';IF J = 1 THENCONTINUE flag1;END IF;I_NUM = I_NUM+1;END LOOP;END LOOP;PRINT '循环结束了,I_NUM='||TO_CHAR(I_NUM)||'!';
END;第1层循环,第1输出!
第2层循环,第1输出!
第1层循环,第2输出!
第2层循环,第1输出!
第1层循环,第3输出!
第2层循环,第1输出!
循环结束了,I_NUM=1!
DMSQL 过程已成功完成
已用时间: 0.441(毫秒). 执行号:1703.
3 游标
3.1 静态游标
静态游标是只读游标,它总是按照打开游标时的原样显示结果集,在编译时就能确定静态游标使用的查询。
3.1.1 隐式游标
隐式游标无需用户进行定义,每当用户在DMSQL程序中执行一个DML语句(INSERT、UPDATE、DELETE、SELECT)或者SELECT…INTO语句时,DMSQL程序都会自动声明一个隐式游标并管理这个游标。对于隐式游标,这四个属性的意义如下:
%FOUND:若没有执行DML或查询语句,返回NULL;若执行了DML或查询语句,判断语句是否影响或查询到了记录,是返回TRUE,否则返回FALSE;
%NOTFOUND:若没有执行DML或查询语句,返回NULL;若执行了DML或查询语句,判断语句是否未能成功影响或查询到记录,是返回TRUE,否则返回FALSE;
%ISOPEN:游标是否打开。是返回TRUE,否返回FALSE。由于系统在语句执行完成后会自动关闭隐式游标,因此隐式游标的%ISOPEN属性永远为FALSE;
%ROWCOUNT:DML语句执行影响的行数,或SELECT…INTO语句返回的行数,非兼容SQLSERVER模式下SELECT语句返回0。
例如,演示%NOTFOUND和%ROWCOUNT使用。
DECLAREV_COUNT INT;
BEGINUPDATE SALES_ORDER_UN SET N1=6666 WHERE SALESMAN='张三';V_COUNT = SQL%ROWCOUNT;IF SQL%NOTFOUND THENPRINT '数据未找到';ELSEPRINT '数据找到了'||'影响到了' || TO_CHAR(V_COUNT)||'行数据';END IF;
END;数据找到了影响到了1行数据
DMSQL 过程已成功完成
已用时间: 00:00:03.632. 执行号:1706.
3.1.2 显式游标
显式游标指向一个查询语句执行后的结果集区域。当需要处理返回多条记录的查询时,应显式地定义游标以处理结果集的每一行。
DECLAREV_EMP_NAME VARCHAR(20);V_SALARY INT;CUR_EMP CURSOR FOR SELECT EMP_NAME,SALARY FROM U_TEST.EMPLOYEES;
BEGINOPEN CUR_EMP; LOOPFETCH CUR_EMP INTO V_EMP_NAME,V_SALARY; EXIT WHEN CUR_EMP%NOTFOUND;PRINT V_EMP_NAME||'的薪资为'||TO_CHAR(V_SALARY);END LOOP;CLOSE CUR_EMP;
END;张三的薪资为8500
李四的薪资为9200
王五的薪资为7500
赵六的薪资为11000
钱七的薪资为6800
DMSQL 过程已成功完成
已用时间: 11.529(毫秒). 执行号:1708.
3.2 动态游标
与静态游标不同,动态游标在声明部分只是先声明一个游标类型的变量,并不指定其关联的查询语句,在执行部分打开游标时才指定查询语句。
DECLAREV_EMP_NAME VARCHAR(20);V_SALARY INT;CUR_EMP CURSOR;
BEGINOPEN CUR_EMP FOR SELECT EMP_NAME,SALARY FROM U_TEST.EMPLOYEES; LOOPFETCH CUR_EMP INTO V_EMP_NAME,V_SALARY; EXIT WHEN CUR_EMP%NOTFOUND;PRINT V_EMP_NAME||'的薪资为'||TO_CHAR(V_SALARY);END LOOP;CLOSE CUR_EMP;
END;张三的薪资为8500
李四的薪资为9200
王五的薪资为7500
赵六的薪资为11000
钱七的薪资为6800
DMSQL 过程已成功完成
已用时间: 11.591(毫秒). 执行号:1709.
3.3 游标引用
引用游标是一种<REF类型名>类型的游标变量。引用游标实现了在程序间传递结果集的功能。
DECLARETYPE EMPTYPE IS REF CURSOR RETURN EMPLOYEES;EMP EMPTYPE;
PROCEDURE PROCESS_EMP(EMP_V IN EMPTYPE)
IS EMPLOYEES EMPLOYEES%ROWTYPE;
BEGINLOOPFETCH EMP_V INTO EMPLOYEES;EXIT WHEN EMP_V%NOTFOUND;DBMS_OUTPUT.PUT_LINE('姓名:'||EMPLOYEES.EMP_NAME || ' 薪资:' || EMPLOYEES.SALARY);END LOOP;
END;
BEGINOPEN EMP FOR SELECT * FROM EMPLOYEES;PROCESS_EMP(EMP);CLOSE EMP;
END;
3.4 游标FOR循环
例如,隐式游标FOR循环。
BEGINFOR EMP_V IN (SELECT * FROM EMPLOYEES)LOOPPRINT EMP_V.EMP_NAME||'的薪资为'||TO_CHAR(EMP_V.SALARY);END LOOP;
END;张三的薪资为8500
李四的薪资为9200
王五的薪资为7500
赵六的薪资为11000
钱七的薪资为6800
DMSQL 过程已成功完成
已用时间: 1.397(毫秒). 执行号:1710.
例如,显式游标FOR循环。
DECLARECUR_EMP CURSOR FOR SELECT * FROM EMPLOYEES;
BEGINFOR EMP_V IN CUR_EMPLOOPPRINT EMP_V.EMP_NAME||'的薪资为'||TO_CHAR(EMP_V.SALARY);END LOOP;
END;张三的薪资为8500
李四的薪资为9200
王五的薪资为7500
赵六的薪资为11000
钱七的薪资为6800DMSQL 过程已成功完成
已用时间: 15.021(毫秒). 执行号:1711.
4 抛出异常
DMSQL程序在应用运行时不可避免地会发生一些错误,这些错误常常并不是DMSQL程序本身的设计和编码问题,而是由于应用运行时由于一些未预计的操作或硬件异常等导致产生超出DMSQL程序预计处理范围的数据等错误,我们将这些错误称为异常。应该在DMSQL程序中对异常进行处理,否则将造成应用的异常退出。
DMSQL程序提供了内置函数SQLCODE和SQLERRM。SQLCODE返回错误码,为一个负数。SQLERRM返回异常的描述信息,为字符串类型。
例如,用户异常处理如下:
DECLAREI_NUM INT:=1;E_EXIT_LOOP EXCEPTION;
BEGINLOOPPRINT '这是第'||TO_CHAR(I_NUM)||'输出!';IF I_NUM%3=0 THENRAISE E_EXIT_LOOP;END IF;I_NUM = I_NUM+1;END LOOP;
EXCEPTIONWHEN E_EXIT_LOOP THENPRINT '这是LOOP 触发的RAISE异常';PRINT SQLCODE ||' '|| SQLERRM;
END;这是第1输出!
这是第2输出!
这是第3输出!
这是LOOP 触发的RAISE异常
-15001 User define exceptionDMSQL 过程已成功完成
已用时间: 0.541(毫秒). 执行号:1712.