PL/SQL 编程(一)基础,变量,分支,循环,异常
SQL和PL/SQL:
SQL 结构化查询语言(Structural Query Language),是用来访问和操作关系型数据库的一种标准通用语言,属于第四代语言(4GL)。可以方便的调用相应语句来去的结果,特点是非过程化,使用的时候不用指明执行的具体方法,不用关注实现的细节,但是某些情况下满足不了复杂业务流程的需求。
PL/SQL是 Procedure Language & Structured Query Language 的缩写。属于第三代语言(3GL),是一种过程化语言。PL/SQL是对SQL语言存储过程语言的扩展,是一种高级数据库程序设计语言,该语言专门用于在各种环境下对Oracle数据库进行访问。除此之外,可以在Oracle数据库的某些客户端工具中,使用PL/SQL语言也是该语言的一个特点。PL/SQL可以向Java一样实现逻辑判断。条件循环和异常处理等。
同传统的SQL相比PL/SQL有以下优点:
1.可以提高程序的运行性能。
2.可以使程序模块化。
3.可以采用逻辑控制语句来控制程序结构。
4.利用处理运行时的错误信息。
5.良好的可移植性。
PL/SQL块
pl/sql的基本单位是块。分为三部分,声明部分,执行部分,异常处理部分。其中执行部分时必须存在的,声明和异常处理可以没有。
--PL/SQL块的结构如下:
DECLARE
--声明部分: 在此声明PL/SQL用到的变量,类型及游标,以及局部的存储过程和函数
BEGIN
-- 执行部分: 过程及SQL 语句 , 即程序的主要部分
EXCEPTION
-- 执行异常部分: 错误处理
END;
变量 常量
变量表示的值是可以变化的,常量初始化后,其值不可改变。
需要注意:pl/sql是一种强类型语言。
如果表示常量,必须用CONSTANT关键字。
标量类型变量:
最简单类型的变量,它本身是单一的值,不包含任何的类型组合,标量类型主要包含数值类型,字符类型,布尔类型,日期类型。还有一种特殊的声明变量类型的方式: %type
引用型变量:
使用%TYPE,利用已存在的数据类型定义新变量的数据类型。最常见的就是把表中字段类型作为变量或常量的数据类型。
使用%TYPE特性的优点在于:
l 所引用的数据库列的数据类型可以不必知道;
l 所引用的数据库列的数据类型可以实时改变,容易保持一致,也不用修改PL/SQL程序。
DECLARE
-- 用%TYPE 类型定义与表相配的字段
TYPE T_Record IS RECORD(
T_no emp.empno%TYPE,
T_name emp.ename%TYPE,
T_sal emp.sal%TYPE );
-- 声明接收数据的变量
v_emp T_Record;
BEGIN
;
DBMS_OUTPUT.PUT_LINE
(TO_CHAR(v_emp.t_no)||' '||v_emp.t_name||' ' || TO_CHAR(v_emp.t_sal));
END;
DECLARE
v_empno emp.empno%TYPE :=&no;
Type t_record is record (
v_name emp.ename%TYPE,
v_sal emp.sal%TYPE,
v_date emp.hiredate%TYPE);
Rec t_record;
BEGIN
SELECT ename, sal, hiredate INTO Rec FROM emp WHERE empno=v_empno;
DBMS_OUTPUT.PUT_LINE(Rec.v_name||'---'||Rec.v_sal||'--'||Rec.v_date);
END;
记录型变量:
它把逻辑相关的、分离的、基本数据类型的变量组成一个整体存储起来,它必须包括至少一个标量型或RECORD 数据类型的成员,称作PL/SQL RECORD 的域(FIELD),其作用是存放互不相同但逻辑相关的信息。在使用记录数据类型变量时,需要先在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。
该类型可以包含一个或多个成员,每个成员类型可以不同。成员可以是标量类型,也可以是引用类型。记录类型适合处理查询语句中有多个列的情况,比如调用某个表的一行记录时用记录类型变量存储这行记录。
--可以用 SELECT语句对记录变量进行赋值,只要保证记录字段与查询结果列表中的字段相配即可。
DECLARE
TYPE test_rec IS RECORD(
Name ) NOT NULL := '胡勇',
Info ));
rec_book test_rec;
BEGIN
rec_book.Name :='胡勇';
rec_book.Info :='谈PL/SQL编程;';
DBMS_OUTPUT.PUT_LINE(rec_book.Name||' ' ||rec_book.Info);
END;
--一个记录类型的变量只能保存从数据库中查询出的一行记录,若查询出了多行记录,就会出现错误。
DECLARE
--定义与hr.employees表中的这几个列相同的记录数据类型
TYPE RECORD_TYPE_EMPLOYEES IS RECORD(
f_name hr.employees.first_name%TYPE,
h_date hr.employees.hire_date%TYPE,
j_id hr.employees.job_id%TYPE);
--声明一个该记录数据类型的记录变量
v_emp_record RECORD_TYPE_EMPLOYEES;
BEGIN
SELECT first_name, hire_date, job_id INTO v_emp_record
FROM employees
WHERE employee_id = &emp_id;
DBMS_OUTPUT.PUT_LINE('雇员名称:'||v_emp_record.f_name
||' 雇佣日期:'||v_emp_record.h_date
||' 岗位:'||v_emp_record.j_id);
END;
使用%ROWTYPE声明记录类型数据
这种声明方式可以直接引用表中的行作为变量类型,同 %type 相似。
使用%ROWTYPE特性的优点在于:
l 所引用的数据库中列的个数和数据类型可以不必知道;
l 所引用的数据库中列的个数和数据类型可以实时改变,容易保持一致,也不用修改PL/SQL程序。
DECLARE
v_empno emp.empno%TYPE :=&no;
rec emp%ROWTYPE;
BEGIN
SELECT * INTO rec FROM emp WHERE empno=v_empno;
DBMS_OUTPUT.PUT_LINE('姓名:'||rec.ename||'工资:'||rec.sal||'工作时间:'||rec.hiredate);
END;
数组类型
是具有相同数据类型的一组成员的集合。每个成员都有一个唯一的下标,它取决于成员在数组中的位置。在PL/SQL中,数组数据类型是VARRAY。
DECLARE
--定义一个最多保存5个VARCHAR(25)数据类型成员的VARRAY数据类型
TYPE reg_varray_type ) );
--声明一个该VARRAY数据类型的变量
v_reg_varray REG_VARRAY_TYPE;
BEGIN
--用构造函数语法赋予初值
v_reg_varray := reg_varray_type
('中国', '美国', '英国', '日本', '法国');
DBMS_OUTPUT.PUT_LINE()||'、'
)||'、'
)||'、'
));
DBMS_OUTPUT.PUT_LINE());
--用构造函数语法赋予初值后就可以这样对成员赋值
v_reg_varray() := '法国';
DBMS_OUTPUT.PUT_LINE());
END;
赋值:赋值要用 := 。
结构控制:
if条件控制:
和Java基本相同。
declare
a );
b );
c );
begin
a := '明';
dbms_output.put_line(a);
b :;
c :;
--分支
if b > c then
dbms_output.put_line('b大于c');
elsif b < c then
dbms_output.put_line('b小于c');
else
dbms_output.put_line('b等于c');
end if;
end;
DECLARE
v_empno employees.employee_id%TYPE :=&empno;
V_salary employees.salary%TYPE;
V_comment );
BEGIN
SELECT salary INTO v_salary FROM employees
WHERE employee_id = v_empno;
THEN
V_comment:= '太少了,加点吧~!';
ELSIF v_salary THEN
V_comment:= '多了点,少点吧~!';
ELSE
V_comment:= '没有薪水~!';
END IF;
DBMS_OUTPUT.PUT_LINE(V_comment);
exception
when no_data_found then
DBMS_OUTPUT.PUT_LINE('没有数据~!');
when others then
DBMS_OUTPUT.PUT_LINE(sqlcode || '---' || sqlerrm);
END;
DECLARE
v_first_name );
v_salary ,);
BEGIN
SELECT first_name, salary INTO v_first_name, v_salary FROM employees
WHERE employee_id = &emp_id;
DBMS_OUTPUT.PUT_LINE(v_first_name||'雇员的工资是'||v_salary);
THEN
DBMS_OUTPUT.PUT_LINE('工资低于10000');
ELSE
THEN
DBMS_OUTPUT.PUT_LINE('工资在10000到20000之间');
ELSE
DBMS_OUTPUT.PUT_LINE('工资高于20000');
END IF;
END IF;
END;
DECLARE
v_first_name );
v_hire_date DATE;
v_bonus ,);
BEGIN
SELECT first_name, hire_date INTO v_first_name, v_hire_date FROM employees
WHERE employee_id = &emp_id;
IF v_hire_date > TO_DATE('01-1月-90') THEN
v_bonus :;
ELSIF v_hire_date > TO_DATE('01-1月-88') THEN
v_bonus :;
ELSE
v_bonus :;
END IF;
DBMS_OUTPUT.PUT_LINE(v_first_name||'雇员的雇佣日期是'||v_hire_date
||'、奖金是'||v_bonus);
END;
case语句
DECLARE
V_grade ) := UPPER('&p_grade');
V_appraisal );
BEGIN
V_appraisal :=
CASE v_grade
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE('Grade:'||v_grade||' Appraisal: '|| v_appraisal);
END;
DECLARE
v_first_name employees.first_name%TYPE;
v_job_id employees.job_id%TYPE;
v_salary employees.salary%TYPE;
v_sal_raise ,);
BEGIN
SELECT first_name, job_id, salary INTO
v_first_name, v_job_id, v_salary
FROM employees WHERE employee_id = &emp_id;
CASE
WHEN v_job_id = 'PU_CLERK' THEN
;
;
END IF;
WHEN v_job_id = 'SH_CLERK' THEN
;
;
END IF;
WHEN v_job_id = 'ST_CLERK' THEN
;
;
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('该岗位不涨工资: '||v_job_id);
END CASE;
DBMS_OUTPUT.PUT_LINE(v_first_name||'的岗位是'||v_job_id
||'、的工资是'||v_salary
||'、工资涨幅是'||v_sal_raise);
END;
循环:
declare
a );
b );
c );
m );
sname );
begin
a := '明';
dbms_output.put_line(a);
b :;
c :;
--分支
if b > c then
dbms_output.put_line('b大于c');
elsif b < c then
dbms_output.put_line('b小于c');
else
dbms_output.put_line('b等于c');
end if;
--循环 1
loop
;
dbms_output.put_line('loop:' || c);
c :;
end loop;
--循环 2
loop
dbms_output.put_line('while:' || b);
b :;
end loop;
--循环 3
.. loop
dbms_output.put_line('for:' || n);
end loop;
end;
异常
编译时的错误不能称为异常。
有三种类型的异常错误:
1. 预定义 ( Predefined )错误
ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。
2. 非预定义 ( Predefined )错误
即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。
3. 用户定义(User_define) 错误
预定义异常一览:

处理异常:
select s.name into sname from z_student s where s.id=m;
dbms_output.put_line('查询结果:' || sname);
exception
when no_data_found then
dbms_output.put_line('无查询结果');
--预定义异常
DECLARE
v_empno employees.employee_id%TYPE := &empno;
v_sal employees.salary%TYPE;
BEGIN
SELECT salary INTO v_sal FROM employees WHERE employee_id = v_empno;
THEN
WHERE employee_id=v_empno;
DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已更新!');
ELSE
DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已经超过规定值!');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
非预定义异常
对于这类异常情况的处理,首先必须对非定义的ORACLE错误进行定义。步骤如下:
1. 在PL/SQL 块的定义部分定义异常情况:
<异常情况> EXCEPTION;
2. 将其定义好的异常情况,与标准的ORACLE错误联系起来,使用EXCEPTION_INIT语句:
PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);
3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。
--删除指定部门的记录信息,以确保该部门没有员工。
, 'FINANCE', 'CHICAGO');
DECLARE
v_deptno departments.department_id%TYPE := &deptno;
deptno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(deptno_remaining, );
/* -2292 是违反一致性约束的错误代码 */
BEGIN
DELETE FROM departments WHERE department_id = v_deptno;
EXCEPTION
WHEN deptno_remaining THEN
DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
自定义异常
步骤如下:
1. 在PL/SQL 块的定义部分定义异常情况:
<异常情况> EXCEPTION;
2. RAISE <异常情况>;
3. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。
then
raise nozero;
end if;
exception
when nozero then
dbms_output.put_line('m不能为0');
--更新指定员工工资,增加100;
DECLARE
v_empno employees.employee_id%TYPE :=&empno;
no_result EXCEPTION;
BEGIN
WHERE employee_id = v_empno;
IF SQL%NOTFOUND THEN
RAISE no_result;
END IF;
EXCEPTION
WHEN no_result THEN
DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
--创建一个函数get_salary, 该函数检索指定部门的工资总和,其中定义了-20991和-20992号错误,分别处理参数为空和非法部门代码两种错误:
CREATE TABLE errlog(
Errcode NUMBER,
Errtext ));
CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER)
RETURN NUMBER
AS
v_sal NUMBER;
BEGIN
IF p_deptno IS NULL THEN
RAISE_APPLICATION_ERROR(, ’部门代码为空’);
ELSIF p_deptno THEN
RAISE_APPLICATION_ERROR(, ’无效的部门代码’);
ELSE
SELECT SUM(employees.salary) INTO v_sal FROM employees
WHERE employees.department_id=p_deptno;
RETURN v_sal;
END IF;
END;
DECLARE
V_salary ,);
V_sqlcode NUMBER;
V_sqlerr );
Null_deptno EXCEPTION;
Invalid_deptno EXCEPTION;
PRAGMA EXCEPTION_INIT(null_deptno,);
PRAGMA EXCEPTION_INIT(invalid_deptno, );
BEGIN
V_salary :);
DBMS_OUTPUT.PUT_LINE('10号部门工资:' || TO_CHAR(V_salary));
BEGIN
V_salary :);
EXCEPTION
WHEN invalid_deptno THEN
V_sqlcode :=SQLCODE;
V_sqlerr :=SQLERRM;
INSERT INTO errlog(errcode, errtext)
VALUES(v_sqlcode, v_sqlerr);
COMMIT;
END inner1;
V_salary :);
DBMS_OUTPUT.PUT_LINE('部门号为20的工资为:'||TO_CHAR(V_salary));
BEGIN
V_salary :=get_salary(NULL);
END inner2;
V_salary :);
DBMS_OUTPUT.PUT_LINE('部门号为30的工资为:'||TO_CHAR(V_salary));
EXCEPTION
WHEN null_deptno THEN
V_sqlcode :=SQLCODE;
V_sqlerr :=SQLERRM;
INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr);
COMMIT;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END outer;
PL/SQL 编程(一)基础,变量,分支,循环,异常的更多相关文章
- Oracle PL/SQL编程之基础
1.简介:pl/sql块由三个部分组成:定义部分.执行部分.例外处理部分,如下所示: declare: /*定义部分---定义常量.变量.游标.例外.复杂数据类型 begin /*执行部分---要执行 ...
- ORACLE PL/SQL编程详解
ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设 ...
- ORACLE PL/SQL编程详解(转)
原帖地址:http://blog.csdn.net/chenjinping123/article/details/8737604 ORACLE PL/SQL编程详解 SQL语言只是访问.操作数据库的语 ...
- [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)
原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日 ...
- 【PL/SQL编程基础】
[PL/SQL编程基础]语法: declare 声明部分,例如定义变量.常量.游标 begin 程序编写,SQL语句 exception 处理异常 end: / 正斜杠表示执行程序快范例 -- Cre ...
- Oracle数据库编程:PL/SQL编程基础
2.PL/SQL编程基础: PL/SQL块: declare 定义部分 begin 执行部分 exception 异 ...
- PL/SQL编程基础(三):数据类型划分
数据类型划分 在Oracle之中所提供的数据类型,一共分为四类: 标量类型(SCALAR,或称基本数据类型) 用于保存单个值,例如:字符串.数字.日期.布尔: 标量类型只是作为单一类型的数据存在,有的 ...
- PL/SQL编程基础(五):异常处理(EXCEPTION)
异常处理 异常产生所带来的问题: 使用EXCEPTION程序块进行异常处理: 实现用户自定义异常. 使用异常可以保证在程序中出现运行时异常时程序可以正常的执行完毕: 用户可以使用自定义异常进行操作. ...
- PL/SQL编程基础
1. PL/SQL块的基础结构 DECLARE /* * 定义部分——定义常量.变量.复杂数据类型.游标.用户自定义异常 */ BEGIN /* * 执行部分——PL/SQL语句和SQL语句 */ E ...
随机推荐
- Mathematica 10 Mac 设置默认工作目录
用SetDirectory命令设置
- java--while、do while、for三种循环体
1.for可以记录执行次数: 2.while.do while的i放在sum的后面和for得到的执行次数和结果是一致的. 1.从执行结果来看,放在前面,虽然执行次数和i放在sum的后面是相同,但是结果 ...
- MQ队列管理
分享一段代码,很实用. 下面这段java代码是我在国外一个论坛上发现的,源地址已经忘了.代码的作用是可以删除正在使用的mq的队列消息,管理mq的人一定知道它的美妙了吧,哈哈. 我拿来改了下,增加了2个 ...
- JavaWeb 后端 <一> 之 Tomcat服务器 - Http协议 学习笔记
1.Web开发概述 1.1服务器上的资源分类: a.静态资源:指web页面中供人们浏览的数据始终是不变.html css js 图片 多媒体 b.动态资源:指web页面中供人们浏览的数据是由程序产生的 ...
- POJ 2342 Anniversary party / HDU 1520 Anniversary party / URAL 1039 Anniversary party(树型动态规划)
POJ 2342 Anniversary party / HDU 1520 Anniversary party / URAL 1039 Anniversary party(树型动态规划) Descri ...
- JS的get和set使用示例
javascript中set与get方法详解 其中get与set的使用方法: 1.get与set是方法,因为是方法,所以可以进行判断. 2.get是得到 一般是要返回的 set 是设置 不用返回 ...
- 关于Mongo的一些坑
和大多数人一样,从Mysql转到Mongo的过程中,思维上经历了很大的转变.下面来说几点我遇到的坑: 1.单文档16M 这个是最多人碰到的,我也碰到过,当然,幸好是因为操作有误,导致这种不正常的大量数 ...
- nodejs 全局变量和全局对象
1.全局对象 所有模块都可以调用 1)global:表示Node所在的全局环境,类似于浏览器中的window对象. 2)process:指向Node内置的process模块,允许开发者与当前进程互动. ...
- 关于用node批量修改文件名
关于node环境的配置和环境变量的配置就不再这个细说了 一.首先按需求找到需要使用的模块 fs和path: const fs=require('fs') const path=require('pat ...
- 【CSS3】使用CSS3线性渐变实现图片闪光划过效果(转)
原文:http://www.nowamagic.net/librarys/veda/detail/2600 资料参考: http://www.cnblogs.com/lhb25/archive/201 ...