第6章:PL/SQL块
--6-19
begin
p3(var_job=>'SALESMAN',i,j,k);
end;
/
declare
cursor cur_emp(var_job in varchar2:='SALESMAN') is select empno,ename,sal from emp where job=var_job;
type record_emp is record
(
x emp.empno%type,
y emp.ename%type,
z emp.sal%type
);
emp_row record_emp;
begin
open cur_emp('MANAGER');
fetch cur_emp into emp_row;
while cur_emp%found loop
dbms_output.put_line(emp_row.x||emp_row.y||emp_row.z);
fetch cur_emp into emp_row;
end loop;
close cur_emp;
end;
/
完整结构:
[declare
变量,常量]
begin
执行部分
[exception
异常处理]
end;
/
简写形式:
begin
执行部分
...
end;
/
6.2变量与常量:
1.变量与常量定义必须在declare中。
合法标识:
必须以字母开头,长度不能超过30个字符。
标识符中不能包含减号“-”和空格。
Oracle标识符不区分大小写。
标识符不能是SQL保留字。
例题:
v_name varchar2(20) --对
2010_name varchar2(20) --错
v-name varchar2(20) --错
v name varchar2(20) --错
user varchar2(20) --错
2.基本数据类型
1)数值类型:
例题:
declar
num_mo number(5,2); --小数位2位,整数位3位
2)字符类型:
char
varchar2
例题:
declare
str varchar2(20);
begin
str:='hello,everyone';
dbms_output.put_line(str);
end;
/
3)日期类型:
declare
d1 date:= sysdate;
d2 date:='10-5月-2018';
或者d2 date:=to_date('10-5月-2018');
4)布尔类型boolean:取值true、false、null
实际使用:
3.变量与常量声明注意事项:
例题:
declare
v_ename varchar2(20);
v_sal number(6,2);
c_tax_rate constant number(3,2):=5.5; --声明常量时,必须为它赋初始值,并且数值不能改
v_hiredate date;
v_valid boolean not null default false;
begin
null; --begin与end之间至少有一条语句
end;
/
6.2.2特殊数据类型
1.%type类型
a)用基本数据类型:
declare
x varchar2(10);
y varchar2(9);
begin
select ename,job into x,y from emp where empno=7369;
sys.dbms_output.put_line(x||'的工作为'||y);
end;
/
b)%type类型
比如在system账户下:
declare
x scott.emp.ename%type;
y scott.emp.job%type;
begin
select ename,job into x,y from scott.emp where empno=7369;
sys.dbms_output.put_line(x||'的工作为'||y);
end;
/
比如在scott账户下:
declare
x emp.ename%type;
y emp.job%type;
begin
select ename,job into x,y from emp where empno=7369;
dbms_output.put_line(x||'的工作为'||y);
end;
/
2.record类型
a)用%type类型
declare
x emp.ename%type;
y emp.job%type;
z emp.sal%type;
begin
select ename,job,sal into x,y,z from emp where empno=7369;
dbms_output.put_line(x||y||z);
end;
/
b)用record类型
declare
type e_r is record
(
x emp.ename%type,
y emp.job%type,
z emp.sal%type
);
e e_r;
begin
select ename,job,sal into e from emp where empno=7369;
dbms_output.put_line(e.x||e.y||e.z);
end;
/
或者:
declare
type e_r is record
(
x varchar2(10),
y varchar2(9),
z number(7,2)
);
e e_r;
begin
select ename,job,sal into e from emp where empno=7369;
dbms_output.put_line(e.x||e.y||e.z);
end;
/
补充:&的用法
declare
x emp.ename%type;
y emp.job%type;
z emp.sal%type;
begin
select ename,job,sal into x,y,z from emp where empno=&员工编号;
dbms_output.put_line(x||y||z);
end;
/
或者:
declare
x emp.ename%type;
y emp.job%type;
z emp.sal%type;
m emp.empno%type;
begin
m:=&员工编号;
select ename,job,sal into x,y,z from emp where empno=m;
dbms_output.put_line(x||y||z);
end;
/
3.%rowtype类型
declare
e emp%rowtype;
begin
select * into e from emp where empno=7369;
dbms_output.put_line(e.ename||e.sal||e.job);
end;
/
6.3流程控制语句
6.3.1选择语句
if语句:
1)单分支
if 条件 then
语句序列;
end if;
2)双分支
if 条件 then
语句序列1;
else
语句序列2;
end if;
3)多分支
if 条件1 then
语句序列1;
elsif 条件2 then
语句序列2;
elsif 条件3then
语句序列3;
...
else
语句序列n;
end if;
case语句:
1)等值比较
case 变量
when 值1 then
语句序列1
when 值2 then
语句序列2
......
when 值n then
语句序列n
else
语句序列n+1
end case;
或者:
case
when 变量=值1 then
语句序列1;
when 变量=值2 then
语句序列2;
......
when 变量=值n then
语句序列n;
else
语句序列n+1;
end case;
例如:
begin
case
when season=1 then
...
when season=2 then
...
......
课本例6-14:
declare
season int:=&季度;
--定义整形变量并赋值
aboutInfo varchar2(50); --存储月份信息
begin
case season --判断季度
when 1 then --若是1季度
aboutInfo := season||'季度包括1,2,3月份';
when 2 then --若是2季度
aboutInfo := season||'季度包括4,5,6月份';
when 3 then --若是3季度
aboutInfo := season||'季度包括7,8,9月份';
when 4 then --若是4季度
aboutInfo := season||'季度包括10,11,12月份';
else --若季度不合法
aboutInfo := season||'季度不合法';
end case;
dbms_output.put_line(aboutinfo); --输出该季度所包含的月份信息
end;
/
2)不等值比较
case
when 不等值表达式1 then
语句序列1
when 不等值表达式2 then
语句序列2
......
when 不等值表达式n then
语句序列n
else
语句序列n+1
end case;
例如:
declare
定义t;
case
when t<5 then
语句序列1;
when t<10 then
语句序列2;
when t<20 then
语句序列3;
......
when t<50 then
语句序列n;
else
语句序列n+1;
end case;
根据员工的工资,修改emp表中的奖金值。工资小于1000元,奖金为100元;工资小于2000元,奖金为80元;工资小于6000元,奖金为50元;其他情况,奖金为30元。(case)
declare
v_sal scott.emp.sal%type;
v_ename scott.emp.ename%type;
v_empno scott.emp.empno%type;
begin
select ename,sal,empno into v_ename,v_sal,v_empno from scott.emp where empno=&no;
case
when v_sal<1000 then
update scott.emp set comm=100 where empno=v_empno;
when v_sal<2000 then
update scott.emp set comm=80 where empno=v_empno;
when v_sal<6000 then
update scott.emp set comm=50 where empno=v_empno;
else
update scott.emp set comm=30 where empno=v_empno;
end case;
end;
/
6.3.2循环语句
1)loop
loop
语句序列;
exit when 条件;
end loop;
--无论条件是否满足,循环体至少执行一次,当when 条件为true,循环结束;条件为false,循环执行。
2) while
while 条件 loop
语句序列;
end loop;
--当条件为true,循环语句执行,条件为false,退出循环。
3) for
for 循环变量 in [reverse] a..b loop
语句序列;
end loop;
说明:例如
for i in 1..100 loop --则i初始值为1,每次加1,变到100
for i in reverse 1..100 loop --则i初始值为100,每次减1,变到1
6.4游标
显示游标、隐式游标
6.4.1 显示游标
declare
声明游标c1
begin
打开游标 有参数的游标:open c1(参数);/ 无参数的游标:或者open c1;或者open c1(); 指针指向第一条记录
读取游标 fetch c1 into 变量; fetch c1 into aa;(aa定义为record类型)(例题6-19)/ fetch c1 into x,y,z;(变量列表)(例题6-20)
关闭游标 close c1
end;
/
定义游标示例:
不带参数的游标:
declare
cursor c1 is select empno,ename,sal from emp where job='CLERK';
带参数的游标:
declare
cursor c1(vj in varchar2:='SALESMAN') is select empno,ename,sal from emp where job=vj;
例题6-19:
不用循环:
declare
cursor cur_emp(var_job in varchar2:='SALESMAN') is select empno,ename,sal from emp where job=var_job;
type record_emp is record
(
x emp.empno%type,
y emp.ename%type,
z emp.sal%type
);
emp_row record_emp;
begin
open cur_emp('MANAGER');
fetch cur_emp into emp_row;
dbms_output.put_line(emp_row.x||emp_row.y||emp_row.z);
fetch cur_emp into emp_row;
dbms_output.put_line(emp_row.x||emp_row.y||emp_row.z);
fetch cur_emp into emp_row;
dbms_output.put_line(emp_row.x||emp_row.y||emp_row.z);
end;
/
使用while循环:
declare
cursor cur_emp(var_job in varchar2:='SALESMAN') is select empno,ename,sal from emp where job=var_job;
type record_emp is record
(
x emp.empno%type,
y emp.ename%type,
z emp.sal%type
);
emp_row record_emp;
begin
open cur_emp('MANAGER');
fetch cur_emp into emp_row;
while cur_emp%found loop
dbms_output.put_line(emp_row.x||emp_row.y||emp_row.z);
fetch cur_emp into emp_row;
end loop;
close cur_emp;
end;
/
例题6-20
declare
cursor cur_emp is select ename,job from emp where empno=7566;
a emp.ename%type;
b emp.job%type;
begin
open cur_emp;
fetch cur_emp into a,b;
dbms_output.put_line(a||' '||b);
close cur_emp;
end;
/
例题6-20【修改】
declare
cursor cur_emp is select ename,job from emp;
a emp.ename%type;
b emp.job%type;
begin
open cur_emp;
fetch cur_emp into a,b;
while cur_emp%found loop
dbms_output.put_line(a||' '||b);
fetch cur_emp into a,b;
end loop;
close cur_emp;
end;
/
例题6-19【修改】
declare
cursor c1(var_job in varchar2:='SALESMAN')
is select empno,ename,sal from emp where job=var_job;
a emp.empno%type;
b emp.ename%type;
c emp.sal%type;
begin
open c1('MANAGER');
fetch c1 into a,b,c;
while c1%found loop
dbms_output.put_line(a||' '||b||' '||c);
fetch c1 into a,b,c;
end loop;
close c1;
end;
/
改成输入参数名:
declare
cursor cur_emp(var_job varchar2:='&job名') is select empno,ename,job from emp where var_job = job;
empno emp.empno%type;
ename emp.ename%type;
job emp.job%type;
begin
open cur_emp;
fetch cur_emp into empno,ename,job;
while cur_emp%found loop
dbms_output.put_line(ename||empno||job);
fetch cur_emp into empno,ename,job;
end loop;
close cur_emp;
end;
/
6.4.4 for循环的游标
在游标的for循环之前,游标自动打开与关闭;每一次循环,fetch语句自动执行一次,将游标指向的当前记录存入循环变量中。
隐式游标:例题6-22
begin
for e_r in (select empno,ename,sal from emp where job='SALESMAN') loop
dbms_output.put(e_r.empno);
dbms_output.put(e_r.ename);
dbms_output.put_line(e_r.sal);
end loop;
end;
/
或者
begin
for i in (select empno,ename,sal from emp where job='SALESMAN') loop
dbms_output.put_line(i.empno||i.ename||i.sal);
end loop;
end;
/
declare
cursor c2 is select * from emp where job='SALESMAN';
begin
for i in c2 loop
dbms_output.put_line(i.empno||i.ename||i.sal);
end loop;
end;
/
显式游标:例题6-23
declare
cursor cur_emp is select empno,ename,sal from emp where job='SALESMAN';
begin
for e_r in cur_emp loop
dbms_output.put(e_r.empno);
dbms_output.put(e_r.ename);
dbms_output.put_line(e_r.sal);
end loop;
end;
/
6.4.3隐式游标
用于增删改(update,delete,insert)语句
例题6-21
begin
update emp set sal=sal*1.2 where job='SALESMAN';
dbms_output.put_line(sql%rowcount);
end;
/
begin
update emp set sal=sal*1.2 where job='SALESMAN';
if sql%notfound then
dbms_output.put_line('无需涨工资');
else
dbms_output.put_line(sql%rowcount);
end if;
end;
/
【补充】
loop循环的游标
输出10号部门的员工的姓名与工资。
方法1:变量列表
declare
cursor emp_c is select ename,sal from emp where deptno=10;
x emp.ename%type;
y emp.sal%type;
begin
open emp_c;
loop
fetch emp_c into x,y;
exit when emp_c%notfound;
dbms_output.put_line(x||y);
end loop;
dbms_output.put_line(emp_c%rowcount);
close emp_c;
end;
/
方法2:record记录类型
declare
cursor emp_c is select ename,sal from emp where deptno=10;
type m_r is record
(x emp.ename%type,
y emp.sal%type);
m m_r;
begin
open emp_c;
loop
fetch emp_c into m;
exit when emp_c%notfound;
dbms_output.put_line(m.x||m.y);
end loop;
dbms_output.put_line(emp_c%rowcount);
close emp_c;
end;
/
方法3:%rowtype(record记录类型的简化形式,无需定义结构体)
declare
cursor emp_c is select ename,sal from emp where deptno=10;
e_r emp%rowtype;
begin
open emp_c;
loop
fetch emp_c into e_r.ename,e_r.sal;
exit when emp_c%notfound;
dbms_output.put_line(e_r.ename||e_r.sal);
end loop;
dbms_output.put_line(emp_c%rowcount);
close emp_c;
end;
/
方法3变形
declare
cursor emp_c is select * from emp where deptno=10;
e_r emp%rowtype;
begin
open emp_c;
loop
fetch emp_c into e_r; --可只写e_r变量,但是查询需变成select * from emp where deptno=10;
exit when emp_c%notfound;
dbms_output.put_line(e_r.ename||e_r.sal);
end loop;
dbms_output.put_line(emp_c%rowcount);
close emp_c;
end;
/
【游标%rowtype,当作数据类型】
1)课本P131,实验题
做法一:
declare
cursor c_e is select * from emp where sal<(select sal from emp where empno=7698);
begin
for r in c_e loop
dbms_output.put_line(r.ename||r.sal);
end loop;
end;
/
做法二:
declare
cursor c_e is select * from emp where sal<(select sal from emp where empno=7698);
r c_e%rowtype;
begin
for r in c_e loop
dbms_output.put_line(r.ename||r.sal);
end loop;
end;
/
2)例题:利用游标从emp表中获取前两行记录,输出ename、job、sal
declare
cursor c1 is select * from emp;
m emp%rowtype;
begin
open c1;
fetch c1 into m;
dbms_output.put_line(m.ename||m.sal);
fetch c1 into m;
dbms_output.put_line(m.ename||m.sal);
end;
/
变化:
declare
cursor c1 is select * from emp;
m c1%rowtype;
begin
open c1;
fetch c1 into m;
dbms_output.put_line(m.ename||m.sal);
fetch c1 into m;
dbms_output.put_line(m.ename||m.sal);
end;
/
--做法一:用记录
declare
type emp_type is record --声明记录类型为emp_type
(
var_ename varchar2(20),
var_sal number,
var_job varchar2(20)
);
empinfo emp_type; --定义变量
begin
select ename,sal,job
into empinfo
from emp
where ename='SMITH';
dbms_output.put_line(empinfo.var_ename||'的职务是'||empinfo.var_job||'薪水为'||empinfo.var_sal);
end;
/
--做法二:直接定义
declare
var_ename varchar2(20);--定义变量
var_sal number; --每一个都是分号
var_job varchar2(20);
begin
select ename,sal,job
into var_ename,var_sal,var_job
from emp
where ename='SMITH';
dbms_output.put_line(var_ename||'的职务是'||var_job||'薪水为'||var_sal);
end;
/
--做法三:用%type定义
declare
var_ename emp.ename%type;--定义变量
var_sal emp.sal%type; --每一个都是分号
var_job emp.job%type;
begin
select ename,sal,job
into var_ename,var_sal,var_job
from emp
where ename='SMITH';
dbms_output.put_line(var_ename||'的职务是'||var_job||'薪水为'||var_sal);
end;
/
--做法四:用%rowtype
declare
rowVar_emp emp%rowtype;
begin
select * into rowVar_emp
from emp
where ename='SMITH';
dbms_output.put_line(rowVar_emp.ename||'的职务是'||rowVar_emp.job||'薪水为'||rowVar_emp.sal);
end;
/
declare
sdname varchar2(20);
sloc varchar2(30);
sdeptno number:='&deptno';
begin
select dname,loc into sdname,sloc from dept where deptno=sdeptno;
dbms_output.put_line('部门名称'||sdname||'所在位置'||sloc);
end;
/
declare
var_Sal emp.sal%type;
var_Comm emp.comm%type;
var_empno number:='&雇员号';
begin
select sal,nvl(comm,0)--nvl来去掉空值
into var_Sal,var_Comm
from emp
where empno=var_empno;
dbms_output.put_line('整体工资'||(var_Sal+var_Comm));
end;
/
职位 增长工资
------------ -----------
Clerk 500
Salesman 1000
Analyst 1500
Otherwise 2000
编写一个PL/SQL程序块, 接受用户任意输入一个雇员号,从emp表中实现上述加薪处理。(提示:使用多分支)
declare
num_empno number:='&雇员号';
var_job emp.job%type;
begin
select job into var_job from emp where empno = num_empno;
case var_job
when 'CLERK' then
update emp set sal=sal+500 where empno=num_empno;
when 'SALESMAN' then
update emp set sal=sal+1000 where empno=num_empno;
when 'ANALYST' then
update emp set sal=sal+1500 where empno=num_empno;
else
update emp set sal=sal+2000 where empno=num_empno;
end case;
end;
/
declare
corsor c1 is select ename from emp;
var_ename ename%type;
begin
open c1;
fetch c1 into var_ename;
for i in c1;
loop
dbms_output.put_line('雇员名字;'||var_name);
end loop;
end;
/
declare
cursor c1 is select dname from dept;
var_dname varchar2(20);
begin
open c1;
fetch c1 into var_dname;
while c1%found loop
dbms_output.put_line(var_dname);
fetch c1 into var_dname;
end loop;
close c1;
end;
/
begin
for emp_record in (select ename,job,sal from emp where deptno=10)
loop
dbms_output.put_line(emp_record.ename||'的工作是:'||emp_record.job||',工资是'||emp_record.sal);
end loop;
end;
/
(要求:使用while循环)
declare
cursor c1 (num_deptno in number:=10)
is select ename,job,sal from emp where deptno=num_deptno;
type record_emp is record --声明记录格式
(
/定义当前记录的成员变量/
a emp.ename%type,
b emp.job%type,
c emp.sal%type
);
emp_row record_emp;–记录变量
begin
open c1(&部门编号);
fetch c1 into emp_row;
while c1%found loop
dbms_output.put_line(emp_row.a||‘的工作是:’||emp_row.b||’,工资是’||emp_row.c);
fetch c1 into emp_row;
end loop;
close c1;
end;
/
(要求:使用for循环)
declare
cursor c1 (num_deptno in number:=&部门编号)
is select ename,job,sal from emp where deptno=num_deptno;
begin
for emp_row in c1 --遍历信息
loop
dbms_output.put_line(emp_row.ename||'的工作是:'||emp_row.job||',工资是'||emp_row.sal);
end loop;
end;
/
--方法一
declare
cursor c1 is select ename from emp where ename like 'A%' or ename like 'S%';
var_ename emp.ename%type; --声明记录格式
begin
open c1;
fetch c1 into var_ename;
while c1%found loop
update emp set sal=sal*(1+0.1) where ename=var_ename;
fetch c1 into var_ename;
end loop;
close c1;
end;
/
--方法二
declare
cursor c is select ename from emp;
x emp.ename%type;
begin
open c;
fetch c into x;
while c%found loop
update emp set sal=sal*(1+0.1) where ename like 'A%' or ename like 'S%';--where 可以放在后
fetch c into x;
end loop;
close c;
end;
/
--方法三
declare
cursor cur_emp is select * from emp where ename like 'A%' or ename like 'S%';
begin
for c in cur_emp --for循环
loop
update emp set sal=sal*1.1 where ename=c.ename;
end loop;
end;
/
declare
cursor c1 is select ename,sal from emp;
type record_emp is record
(
var_ename emp.ename%type,
num_sal emp.sal%type
);
emp_row record_emp;
begin
open c1;
fetch c1 into emp_row;
while c1%found loop
if emp_row.num_sal*(1+0.1)<5000 then
update emp set sal=sal*(1+0.1) where ename=emp_row.var_ename;
end if;
fetch c1 into emp_row;
end loop;
close c1;
end;
/
--创建函数
--自己
create or replace function f1(num_deptno number) return number is
begin
select avg(sal) into num_avg_pay from emp where deptno=num_deptno; --某个部门的平均工资
return(round(num_avg_pay,2)); --返回平均工资
end;
/
--老师
create or replace function f3(num_d in number) return number is
x number;
begin
select avg(sal) into x from emp where deptno=num_d;
return x;
end;
/
--调用函数:
declare
y number;
begin
y:=f3(10);
dbms_output.put_line(y);
end;
/
begin
dbms_output.put_line(f3(10));
end;
/
--创建函数:
create or replace function f1 return date is
a date;
begin
select ename,sal into a from emp where empno=7369;
return a;
end;
/
set serveroutput on;
--调用函数:
declare
x varchar(2);
y varchar(2);
begin
x:=f1(a);
y:=f1(b);
dbms_output.put_line(x||y);
end;
/
declare
var_ename varchar2(50);
var_job varchar2(50);
cursor c1 is select ename,job from emp where empno = 7566;
begin
open c1;
fetch c1 into var_ename,var_job;
dbms_output.put_line('编号是7566的雇员名称为:'||var_ename||'职务是'||var_job);
close c1;--关闭
end;
/
--变量列表
declare
var_ename varchar2(50);
var_job varchar2(50);
cursor c1 is select ename,job from emp;
begin
open c1;
fetch c1 into var_ename,var_job;
while c1%found loop
dbms_output.put_line(var_ename||':'||var_job);
fetch c1 into var_ename,var_job;
end loop;
close c1;
end;
/