PL/SQL
什么是PL/SQL?
- PL/SQL是一种程序语言,叫做过程化SQL语言(Procedure·Language/SQL)。
- PL/SQL是Oracle数据库对SQL语言的扩展。在普通SQL语句的使用上增加了编程语言的特点。
- PL/SQL是面向过程的语言
PL/SQL的语法结构
PL/SQL块的基本结构
DECLARE
/*
*声明部分--声明变量、常量、复杂数据类型、游标等
*/
BEGIN
/*
*执行部分--PL/SQL语句和SQL与语句
*/
EXECPTION
/*
*异常处理部分--处理运行错误
*/
END; --块结束标记
例子
SET SERVEROUTUT ON
BEGIN
--打印输出
DBMS_OUTPUT.PUT_LINE('hello everyone!')
END;
PL/SQL块的分类
- 匿名块:动态构造、只能执行一次 子程序:储存在数据库中的存储过程、函数及包等。当在
- 数据库上建立好后可以在其它程序中调用它们。
- 触发器:当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。
PL/SQL的变量类型
标识符
- 当编写PL/SQL块时,为了临时存储数据,需要定义变量和常量。那么变量和常量的定义是需要满足标识符的限制要求的:
- 标识符名不能超过三十个字符
- 第一个字符必须是字母
- 不分大小写
- 不能用‘-‘(减号)
- 注意:尽量不把变量名声明成和表中字段名一样的值
变量的命名方法
为了代码的可读性,需遵循以下编码规则
标识符 | 命名规则 | 例子 |
---|---|---|
程序常量 | v_name | v_sal |
程序变量 | c_name | c_pi |
游标变量 | name_curror | emp_curror |
异常标识 | e_name | e_integrity_error |
记录类型 | name_record | emp_record |
变量的类型
- 数值类型:NUMBER(p,s)、INT、FLOAT等
- 字符类型:CHAR(n)、VARCHAR2(n)
- 日期类型:DATE
- 布尔类型:BOOLEAN
变量的大小写规则
- 当编写SQL语句和PL/SQL语句时,既可以采用大写格式,也可以采用小写格式。但是为了程序的可读性,应该尽量按照以下规则
- SQL关键字大写,如:SELECT、UPDATE等
- PL/SQL关键字大写,如:DECLARE、BEGIN、END等
- 数据类型大写,如:INT、DATE等
- 标识符和参数小写,如:v_sal等
- 数据库对象和列小写,如:emp、sal等
注释
单行注释:-- 注释内容
多行注释:/* 注释内容 */
PL/SQL的引用型变量和记录型变量
-
在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据。在这种情况下,变量应该拥有与表列相同的类型。
-
举例
DECLARE
v_name varchar2(10);
v_sal number(7,2);
BEGIN
SELECT ename,sal INTO v_name,v_sal FROM emp WHERE empon = 7788;
--打印姓名和薪水
DBMS_OUTPUT.PUT_LINE(v_name || ' 的工资是 :' || v_sal);
END;
以上的变量都为硬性编码,当数据表字段类型发生变化时,变量类型也要随之改变。非常的不便。
引用型变量
- 应用型变量:是指其数据类型与已经定义的某个数据变量的类型相同,或者与数据库表的某个列的数据类型相同。
-
v_name emp.ename%TYPE;
-
举例
-
-- 引用型变量
DEClARE
v_name emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
--给变量赋值
SELECT ename,sal
INTO v_name,v_sal
FROM emp
WHERE empno = 7788;
--打印输出
DBMS_OUTPUT.PUT_LINE( v_name || ' 的工资是 :' || v_sal );
END;
记录型变量
- PL/SQL提供 %ROWTYPE 操作符,返回一个记录类型,其数据类型和数据库表的数据结构相一致。
- emp_record emp%ROWTYPR;
- 举例(记录型变量相当于记录一整行完整的表记录,通过“变量名.列名”获取其值)
-- 记录型变量
DEClARE
emp_record emp%ROWTYPE;
BEGIN
--给变量赋值
SELECT*
INTO emp_record
FROM emp
WHERE empno = 7788;
--打印输出
DBMS_OUTPUT.PUT_LINE( emp_record.name || ' 的工资是 :' || emp_record.sal );
END;
PL/SQL的运算符
算数运算符
运算符 | 意义 |
---|---|
+ | 加号 |
- | 减号 |
* | 乘号 |
/ | 除号 |
** | 乘方 |
-- 算数运算符
DEClARE
v_num1 NUMBER(3) :=10;
v_num2 NUMBER(3) :=2;
BEGIN
DBMS_OUTPUT.PUT_LINE(v_num1 + v_num1);
DBMS_OUTPUT.PUT_LINE(v_num1 - v_num1);
DBMS_OUTPUT.PUT_LINE(v_num1 * v_num1);
DBMS_OUTPUT.PUT_LINE(v_num1 / v_num1);
DBMS_OUTPUT.PUT_LINE(v_num1 ** v_num1);
END;
关系运算符
运算符 | 意义 |
---|---|
= | 等于 |
<> , != , ~= , ^= | 不等于 |
< | 大于 |
> | 小于 |
<= | 小于等于 |
>= | 大于等于 |
--“ &n1 ”替代变量,运行程序时,会提示用户输入值n1
DECLARE
v_num1 NUMBER(2) := &n1;
v_num2 NUMBER(2) := &n2;
BEGIN
IF (v_num1 = v_num2) THEN
DBMS_OUTPUT.PUT_LINE('num1等于num2');
ELSIF(v_num1 < v_num2) THEN
DBMS_OUTPUT.PUT_LINE('num1小于num2');
ELSIF(v_num1 > v_num2) THEN
DBMS_OUTPUT.PUT_LINE('num1大于num2');
END IF;
IF (v_num1 <> v_num2) THEN
DBMS_OUTPUT.PUT_LINE('num1不等于num2');
END IF;
END;
比较运算符
运算符 | 意义 |
---|---|
IS NULL | 是空值 |
BRTWEEN…AND | 介于俩者之间 |
IN | 等于列表中的某个值 |
--比较运算符
DECLARE
--&n1是替代变量,在执行程序时会提示输入值
v_num1 NUMBER(2):= &n1;
BEGIN
IF(v_num1 BETWEEN 5 AND 10 )THEN
DBMS_OUTPUT.PUT_LINE('num1在5到10之间');
ELSE
DBMS_OUTPUT.PUT_LINE('num1不在5到10之间');
END IF;
IF(v_num1 IN(3,8,10) )THEN
DBMS_OUTPUT.PUT_LINE('num1等于3,8,10中的一个值');
ELSE
DBMS_OUTPUT.PUT_LINE('num1不等于3,8,10中的一个值');
END IF;
IF(v_num1 IS NULL)THEN
DBMS_OUTPUT.PUT_LINE('num1为空');
ELSE
DBMS_OUTPUT.PUT_LINE('num1不为空');
END IF;
END;
逻辑运算符
运算符 | 意义 |
---|---|
AND | 逻辑与 |
OR | 逻辑或 |
NOT | 取反,如 IS NOT NULL,NOT IN |
--逻辑运算符
DECLARE
v_b1 BOOLEAN := &n1;
v_b2 BOOLEAN := &n2;
BEGIN
IF(v_b1 AND v_b2)THEN
DBMS_OUTPUT.PUT_LINE('AND--TRUE');
END IF;
IF(v_b1 OR v_b2)THEN
DBMS_OUTPUT.PUT_LINE('OR--TRUE');
END IF;
IF(NOT v_b1)THEN
DBMS_OUTPUT.PUT_LINE('v_b1取反为TRUE');
END IF;
END;
变量赋值
- 变量赋值
- variable := expression;
- 字符及数字运算特点
- 空值加数字认识空值:NULL + <数字> = NULL
- 空值连接字符,结果仍为字符: NULL || <字符串> = <字符串>
PL/SQL的条件控制语句
IF语句
- 举例1–简单的IF语句
--输入员工号,判断员工工资, 显示工资小于3000的员工姓名及工资。
--简单的IF语句
DECLARE
v_name emp.ename%TYPE;
v_sal emp.sal%TYPE;
BEGIN
SELECT ename,sal
INTO v_name,v_sal
FROM emp
WHERE empno = &no;
IF v_sal <3000 THEN
DBMS_OUTPUT.PUT_LINE(v_name||'的工资是:'||v_sal);
END IF;
END;
- 举例2–二重分支IF语句
--输入员工号,判断员工工资,将工资小于3000的员工工资涨200,并显示涨工资的员工姓名,其他员工显示员工姓名及工资。
--二重分支语句
DECLARE
v_name empnew.ename%TYPE;
v_sal empnew.sal%TYPE;
v_empno empnew.empno%TYPE := &no;
BEGIN
SELECT ename,sal
INTO v_name,v_sal
FROM empnew
WHERE empno = v_empno;
IF v_sal <3000 THEN
UPDATE empnew set sal = sal + 200 where empno = v_empno;
COMMIT;
DBMS_OUTPUT.put_line(v_name||'涨工资了');
ELSE
DBMS_OUTPUT.put_line(v_name||'的工资是:'||v_sal);
END IF;
END;
- 举例3–多重分支IF语句
--输入员工号,判断员工工资, 工资小于2000,显示低收入,工资小于6000,显示中等收入,其它显示高收入。
--多重分支语句
DECLARE
v_name empnew.ename%TYPE;
v_sal empnew.sal%TYPE;
BEGIN
SELECT ename,sal
INTO v_name,v_sal
FROM empnew
WHERE empno = &no;
IF v_sal<2000 THEN
DBMS_OUTPUT.PUT_LINE(v_name||'的工资是:'||v_sal||' 属于低收入');
ELSIF v_sal<6000 THEN
DBMS_OUTPUT.PUT_LINE(v_name||'的工资是:'||v_sal||' 属于中等收入');
ELSE
DBMS_OUTPUT.PUT_LINE(v_name||'的工资是:'||v_sal||' 属于高收入');
END IF;
END;
CASE语句
- 举例1–等值比较
--输入成级等级,判断属于哪个层次,并打印输出
--CASE 等值比较
DECLARE
v_grade char(1) := '&no';
BEGIN
CASE v_grade
WHEN 'A' THEN
DBMS_OUTPUT.PUT_LINE('优秀');
WHEN 'B' THEN
DBMS_OUTPUT.PUT_LINE('中等');
WHEN 'C' THEN
DBMS_OUTPUT.PUT_LINE('一般');
ELSE
DBMS_OUTPUT.PUT_LINE('输入有误');
END CASE;
END;
- 举例2–非等值比较
--输入员工号,获取员工工资,判断工资,如果工资小于1500,补助加100,如果工资小于2500,补助加80,如果工资小于5000,补助加50.
--CASE 非等值比较
DECLARE
v_sal empnew.sal%TYPE;
v_empno empnew.empno%TYPE := &no;
BEGIN
SELECT sal
INTO v_sal
FROM empnew
WHERE empno = &no;
CASE
WHEN v_sal<1500 THEN
UPDATE empnew set comm = nvl(comm,0)+100 WHERE empno = v_empno;
WHEN v_sal<2500 THEN
UPDATE empnew set comm = nvl(comm,0)+80 WHERE empno = v_empno;
WHEN v_sal<5000 THEN
UPDATE empnew set comm = nvl(comm,0)+50 WHERE empno = v_empno;
--COMMIT;
END CASE;
END;
#PL/SQL的循环语句
- 基本循环
--基本循环
DECLARE
v_cnt INT :=1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(v_cnt);
EXIT WHEN v_cnt = 10;
v_cnt := v_cnt+1;
END LOOP;
END;
- while循环
--while循环
DECLARE
v_cnt INT :=1;
BEGIN
WHILE v_cnt<=10 LOOP
DBMS_OUTPUT.PUT_LINE(v_cnt);
v_cnt := v_cnt+1;
END LOOP;
END;
- for循环
--IN 下限 1,上限10 “REVERSE” 代表递减,如果去掉“REVERSE”的话,就是打印1,2,3...10;
BEGIN
FOR i IN REVERSE 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(i);
END LOOP;
END;
PL/SQL的嵌套循环与退出语句
嵌套循环和标号
- 嵌套循环是指在一个循环语句中嵌入另一个循环语句
- 标号用于标记嵌套块或嵌套循环
- 使用<<lable_name>>定义标号
--嵌套循环
DECLARE
v_result INT;
BEGIN
<<outter>>
FOR i IN 1..5 LOOP
<<inter>>
FOR j IN 1..5 LOOP
v_result:=i;
EXIT outter WHEN i=4;
END LOOP inter;
DBMS_OUTPUT.PUT_LINE('内'||v_result);
END LOOP outter;
DBMS_OUTPUT.PUT_LINE('外'||v_result);
END;
EXIT和EXIT WHEN语句
- EXIT语句用于直接退出当前循环
- EXIT WHERE语句用于在满足特定条件时退出当前循环
--CONTINUE
DECLARE
v_cnt INT :=0;
BEGIN
LOOP
v_cnt := v_cnt+1;
CONTINUE WHEN v_cnt = 5;
DBMS_OUTPUT.PUT_LINE(v_cnt);
EXIT WHEN v_cnt = 10;
END LOOP;
END;
PL/SQL的顺序语句
GOTO语句
- GOTO语句用于跳转到特定标号处执行语句
- GOTO lable_name;
- 注意:当使用GOTO跳转到特定标号时,标号后至少要包含一条执行语句
--GOTO语句
DECLARE
v_cnt INT := 1;
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE(v_cnt);
IF v_cnt=10 THEN
--EXIT;
GOTO end_loop;
END IF;
v_cnt := v_cnt + 1;
END LOOP;
<<end_loop>>
DBMS_OUTPUT.PUT_LINE('循环结束');
END;
NULL语句
- NULL语句不会执行任何操作,并且会直接将控制传递到下一个语句,使用该语句的主要目的是提高PL/SQL的可读性
- 举例
--根据输入的员工号,判断员工的工资,如果工资小于3000,将该员工的补助加工资的2%,
并打印输某员工的奖金更新了
--NULL语句
DECLARE
v_sal empnew.sal%TYPE;
v_name empnew.ename%TYPE;
BEGIN
SELECT ename,sal
INTO v_name,v_sal
FROM empnew
WHERE empno = &no;
IF v_sal<3000 THEN
UPDATE empnew set comm = nvl(comm,0)+sal*0.2 WHERE ename=v_name;
COMMIT;
DBMS_OUTPUT.PUT_LINE(v_name||'的奖金更新了');
ELSE
NULL;
END IF;
END;