Oracle PL/SQL 程序设计基础

最近项目在做版本升级,涉及到原有功能的表结构修改,需要将旧数据转移到新库中,项目上定的方案是在旧数据库中通过存储过程生成新数据库的INSERT语句。故对此块内容做了复习整理。


通过一个简单的例子分析PL/SQL程序块结构
Oracle PL/SQL 程序设计基础_第1张图片

  • 声明部分
    • 用于声明变量、常量、游标(cursor)、记录类型(record type)
  • 执行部分
    • 用于执行各种对数据库操作的语句和对异常进行处理的逻辑

声明变量

--格式:变量名 数据类型;
v_name VARCHAR2(128);

声明常量

--格式: 变量名 CONSTRANT 数据类型 := value;
v_days_in_year CONSTRANT INTEGER := 365;

PL/SQL 数据类型


执行部分逻辑是按从上到下的顺序执行的,PL/SQL 支持条件选择语句、循环语句

  • 条件选择
    • IF
    • CASE

IF 语句最简形式

IF condition THEN
	DBMS_OUTPUT.PUT_LINE('当condition为TRUE时,执行');
END IF;

IF 语句扩展形式

IF condition1 THEN
	DBMS_OUTPUT.PUT_LINE('当condition1为TRUE时,执行');
ELSIF condition2 THEN
	DBMS_OUTPUT.PUT_LINE('当condition2为TRUE时,执行');
ELSE
	DBMS_OUTPUT.PUT_LINE('当condition1为FALSE且condition2为FALSE时,执行');
END IF;

一个IF语句最多只能有一个ELSE分支,可以有0个多个 ELSIF condition THEN分支

CASE 语句最简形式

CASE age
	WHEN 10 THEN 
		DBMS_OUTPUT.PUT_LINE('当age值为10时,执行');
END CASE;

CASE 语句扩展形式

CASE age
	WHEN 10 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为10时,执行');
	WHEN 20 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为20时,执行');
	WHEN 30 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为30时,执行');
	ELSE
		DBMS_OUTPUT.PUT_LINE('当age值为其它值时,执行');		
END CASE;

一个CASE语句最多只能有一个ELSE分支,可以有一个或多个WHEN THEN分支

CASE 语句变形

CASE
	WHEN age = 10 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为10时,执行');
	WHEN age = 20 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为20时,执行');
	WHEN age = 30 THEN
		DBMS_OUTPUT.PUT_LINE('当age值为30时,执行');
	ELSE
		DBMS_OUTPUT.PUT_LINE('当age值为其它值时,执行');		
END CASE;

CASE 语句赋值给变量,THEN后面的语句不要加;

appraisal :=
CASE
	WHEN grade = 'A' THEN '优'
	WHEN grade = 'B' THEN '良'
	WHEN grade = 'C' THEN '差'
	ELSE ''
END CASE;
  • 循环
    • LOOP
    • FOR
    • WHILE

LOOP

num NUMBER := 0;
total NUMBER := 0;
LOOP
	num := num + 1;
	total := total + num;
	EXIT WHEN num = 10;--当num=10时,退出循环
END LOOP;
	DBMS_OUTPUT.PUT_LINE(total);
--退出循环
EXIT WHEN condition;
--退出当前循环进入下一次循环
CONTINUE WHEN condition;

FOR

FOR item IN 1..10 LOOP
	DBMS_OUTPUT.PUT_LINE(item);
END LOOP;

每次迭代的步长都是1,当在IN关键字后面加上REVERSE关键字时,将反转遍历的顺序,在上例中将变为从10~1

WHILE

WHILE condition LOOP
	DBMS_OUTPUT.PUT_LINE();
	condition := FALSE;
END LOOP;

声明记录

--格式: 变量名 表名.字段名%TYPE;
v_name employee.name%TYPE;
--格式: 变量名 表名%ROWTYPE;
v_row employee%ROWTYPE;

表名.字段名%TYPE : 用于单个字段
表名%ROWTYPE : 用于表中的一行记录
使用以上两种方式定义变量的数据类型,使声明的变量的数据类型将与指定表中指定的字段的数据类型始终保持一致

如果我们需要定义一个变量存储多个字段(大于一个字段但小于表中的全部字段 或 多个字段来自多个表)的值时,我们可以声明一个record type

TYPE employeeAddrType IS RECORD(
	name VARCHAR2(128),
	addr VARCHAR2(256)
);

v_employee_adr employeeAddrType;

游标
游标的使用由以下几步操作构成:

  1. 声明游标
  2. 打开游标
  3. 逻辑处理
  4. 关闭游标
DECLARE
	--声明游标
	CURSOR my_cursor IS SELECT * FROM employee;
BEGIN
	--打开游标
	OPEN my_cursor;
	--逻辑处理
	LOOP
		EXIT WHEN my_cursor%NOTFOUND;
		DBMS_OUTPUT.PUT_LINE(my_cursor.name);
	END LOOP;
	--关闭游标
	CLOSE my_cursor;
END;

将游标中的数据赋值到指定的变量中

FETCH my_cursor INTO v_row;

使用游标更新数据时,在声明游标的结尾需要使用FOR UPDATE,例如:

CURSOR my_cursor IS SELECT * FROM employee FOR UPDATE;

在逻辑处理部分的UPDATE语句中使用WHERE CURRENT OF 游标名指定更新当前行

UPDATE employee SET name = name||'TEST' WHERE CURRENT OF my_cursor;

如何传参到游标中呢?
在游标声明处指定参数,例如:

CURSOR my_cursor(v_id employee.id%TYPE) IS SELECT * FROM employee WHERE id=v_id;

声明了变量后如何使用呢,在打开游标处设置参数值

OPEN my_cursor(1);

过程

CREATE OR REPLACE PROCEDURE procedure_name
	IS
	--声明变量
BEGIN
	--逻辑处理
END procedure_name;

上面的存储过程是无参的,而实际工作中我们可能会遇到需要传参或返回值的情况
参数有三种模式,分为:

  • 输入参数: in
  • 输出参数: out
  • 输入输出参数: in out
    默认模式为: in
CREATE OR REPLACE PROCEDURE procedure_name(
	business_type in varchar2(4),
	apply_code in varchar2(32),
	business_stauts out varchar2(4)
) IS
	--声明变量
	v_business_status varchar2(4);
	v_sql varchar2(200);
BEGIN
	--逻辑处理
	v_sql := 'SELECT business_status INTO v_business_status FROM dp_c_business_apply where business_type = '''||business_type||''' and apply_code = '''||apply_code||'';'
	execute immediate v_sql;
	business_status := v_business_status;
END procedure_name;

调用存储过程

DECLARE
v_status varchar2(200);
BEGIN
EXECUTE  procedure_name('BS01','201907200000001',v_status);
END;

在上面的例子中我们是按各参数的位置进行传值的,我们还可以按参数名称进行传值

v_status varchar2(200);
BEGIN
EXECUTE  procedure_name(business_type=>'BS01',apply_code=>'201907200000001',business_status=>business_status);
END;

你可能感兴趣的:(水滴石穿)