Oracle_PL/SQL(2) 过程控制

0.检索单行数据
0.1使用标量变量接受数据
例1: 7788
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
select ename,sal into v_ename,v_sal from emp where empno=&no;
dbms_output.put_line('职员号:'||&no||' 职员名:'||v_ename);
end;

0.2嵌入SELECT语句注意事项:
使用SELECT INTO语句时,必须要返回一条数据,并且只能返回一条数据
no_date_found:
select into没有返回数据
too_many_rows:
select into返回多条数据
例2:
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
select ename,sal into v_ename,v_sal from emp where deptno=&deptno;
dbms_output.put_line('部门编号:'||&deptno||' 职员名:'||v_ename);
end;
where子句使用注意事项:
使用的变量名不能与列名相同,否则触发TOO_MANY_ROWS例外.
例3:
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
empno emp.empno%type;
begin
empno:=&no;
select ename,sal into v_ename,v_sal from emp where empno=empno;
dbms_output.put_line('职员编号:'||&no||' 职员名:'||v_ename);
end;


PL/SQL控制结构
1.按顺序执行语句
declare
v_sal number;
v_avg number;
begin
select avg(sal) into v_avg from emp;
dbms_output.put_line('平均工资:'||v_avg);
select sal into v_sal from emp where empno=7788;
dbms_output.put_line('职员号7788人员的工资:'||v_sal);
end;

2.条件分支语句
2.1简单条件判断
语法1:
if 逻辑表达式1 then
语句1;
end if;
例1:
declare
v_sal number;
v_avg number;
begin
select avg(sal) into v_avg from emp;
select sal into v_sal from emp where empno=7788;
if v_sal>v_avg then
dbms_output.put_line('职员号7788人员的工资'||v_sal||'大于平均工资'||v_avg);
end if;
end;
例2:接收参数
declare
v_sal number(6,2);
begin
select sal into v_sal from emp where lower(ename)=lower('&name');
dbms_output.put_line('输入的员工姓名是:'||'&name');
if v_sal<2000 then
update emp set sal=v_sal+200 where lower(ename)=lower('&name');
dbms_output.put_line('给员工:'||'&name'||'工资增加了200.');
end if;
end;

2.2二重条件分支
语法2:
if 逻辑表达式1 then
语句1;
else
语句2;
end if;
例1:
declare
v_sal number;
v_avg number;
begin
select avg(sal) into v_avg from emp;
select sal into v_sal from emp where empno=7788;
if v_sal>v_avg then
dbms_output.put_line('职员号7788人员的工资'||v_sal
||'大于平均工资'||v_avg);
else
dbms_output.put_line('职员号7788人员的工资'||v_sal
||'小于等于平均工资'||v_avg);
end if;
end;
例2:接收参数 7788
declare
v_comm number(6,2);
begin
select comm into v_comm from emp where empno=&no;
dbms_output.put_line('输入的员工编号是:'||'&no');
if v_comm is null then
update emp set comm=200 where empno=&no;
dbms_output.put_line('给员工编号是:'||'&no'||'的发200奖金.');
else
update emp set comm=comm+100 where empno=&no;
dbms_output.put_line('给员工编号是:'||'&no'||'奖金增加了100.');
end if;
end;

2.3多重条件分支
语法3:
if 逻辑表达式1 then
语句1;
elsif 逻辑表达式2 then
语句2
...
else
语句3;
end if;
例1:
declare
v_sal number;
v_avg number;
begin
select avg(sal) into v_avg from emp;
select sal into v_sal from emp where empno=7788;
if v_sal>v_avg then
dbms_output.put_line('职员号7788人员的工资'||v_sal
||'大于平均工资'||v_avg);
elsif v_sal<v_avg then
dbms_output.put_line('职员号7788人员的工资'||v_sal
||'小于平均工资'||v_avg);
else
dbms_output.put_line('职员号7788人员的工资'||v_sal
||'等于平均工资'||v_avg);
end if;
end;

例2:接收参数 7788
declare
v_empno number;
v_job emp.job%type;
begin
v_empno:=&no;
select lower(job) into v_job from emp where empno=v_empno;
dbms_output.put_line('输入的员工编号是:'||'&no');
if v_job='manager' then
update emp set comm=nvl(comm,0)+200 where empno=v_empno;
dbms_output.put_line('按照员工的职位'||v_job||'给员工编号是:'
||v_empno||'奖金增加了200.');
elsif v_job='analyst' then
update emp set comm=nvl(comm,0)+100 where empno=v_empno;
dbms_output.put_line('按照员工的职位'||v_job||'给员工编号是:'
||v_empno||'奖金增加了100.');
else
update emp set comm=nvl(comm,0)+50 where empno=v_empno;
dbms_output.put_line('按照员工的职位'||v_job||'给员工编号是:'
||v_empno||'奖金增加了50.');
end if;
end;

2.4 CASE语句:
在CASE语句中使用单一选择符进行等值比较
语法1:
case 表达式
when 表达式1 then 语句1; --表达式与表达式1相等时执行语句1
when 表达式2 then 语句2; --同上
...
else
默认语句; --表达式与上述各表达式都不相等时执行默认语句
end case;
例1:
declare
v_deptno emp.deptno%type;
begin
v_deptno:=&no;
dbms_output.put_line('输入的部门编号是:'||v_deptno);
case v_deptno
when 10 then
update emp set comm=100 where deptno=v_deptno;
dbms_output.put_line('给部门编号'||v_deptno||'的职员是发100元奖金');
when 20 then
update emp set comm=80 where deptno=v_deptno;
dbms_output.put_line('给部门编号'||v_deptno||'的职员是发80元奖金');
when 30 then
update emp set comm=50 where deptno=v_deptno;
dbms_output.put_line('给部门编号'||v_deptno||'的职员是发50元奖金');
else
dbms_output.put_line('部门编号不存在');
end case;
end;

2.5 在CASE语句中使用多种条件比较
语法2:
case
when 逻辑表达式1 then 语句1; --逻辑表达式1为真时执行语句1
when 逻辑表达式2 then 语句2; --同上
...
else
默认语句; --上述各逻辑表达式都不为真时执行默认语句
end case;

例2:
declare
v_empno emp.empno%type;
v_sal emp.sal%type;
begin
v_empno:=&no;
dbms_output.put_line('输入的职员编号是:'||v_empno);
select sal into v_sal from emp where empno=v_empno;
case
when v_sal<1000 then
update emp set comm=100 where empno=v_empno;
dbms_output.put_line('给工资'||v_sal||'小于1000的职员发100元奖金');
when v_sal<2000 then
update emp set comm=80 where empno=v_empno;
dbms_output.put_line('给工资'||v_sal||'小于2000的职员发80元奖金');
when v_sal<3000 then
update emp set comm=50 where empno=v_empno;
dbms_output.put_line('给工资'||v_sal||'小于3000的职员发50元奖金');
else
dbms_output.put_line('给工资大于等于3000的职员不发奖金');
end case;
end;


3.循环语句
分类:loop循环,while循环,for循环
create table temp_table (
num_col number(8),
char_col varchar2(200)
);

3.1 loop循环
语法:
loop
语句;
end loop;
loop循环没有退出条件,语句被无限次地执行。
一定要包含EXIT语句,定义循环控制变量,并在循环体内改变循环控制变量的值。
循环退出exit
exit when 条件;
if 条件 then
exit;
end if;

declare
v_counter number:=1;
begin
loop
insert into temp_table values (v_counter,'loop循环');
v_counter:=v_counter+1;
if v_counter>=10 then
exit;
end if;
--exit when v_counter>50;
end loop;
end;

3.2 while循环
语法:
while 条件 loop
语句;
end loop;

每次循环前对条件进行判断,条件为真则语句被执行;否则循环终止。
declare
v_counter number:=1;
begin
while v_counter<=50 loop
insert into temp_table values (v_counter,'while循环');
v_counter:=v_counter+1;
end loop;
end;

while中仍可以使用exit退出循环。
declare
v_counter number:=1;
begin
while v_counter<=50 loop
insert into temp_table values (v_counter,'while循环exit');
v_counter:=v_counter+1;
exit when v_counter>20;
end loop;
end;

3.3 数字式FOR循环
使用FOR循环时,ORACLE会隐含定义循环控制变量.
语法:
for counter in[reverse] lower_bound..upper_bound loop
statement1;
statement2;
.......
end loop;
counter是循环控制变量,并且该变量由ORACLE隐含定义,不需要显示定义;
lower_bound和upper_bound分别对应循环控制变量的上下界值.
默认情况下,FOR循环,每次会自动增一,指定REVERSE选项时,每次循环控制变量会减一
例1:
begin
for v_counter in 1..10 loop
insert into temp_table values (v_counter,'for循环');
end loop;
end;
例2:reverse 从大向小循环
begin
for v_counter in reverse 1..10 loop
insert into temp_table values (v_counter,'for循环reverse');
end loop;
end;

3.4 隐式游标for循环
begin
for rs in (select * from emp) loop
insert into temp_table values (rs.empno,rs.ename);
end loop;
end;

begin
for rs in (select * from emp where deptno=10 ) loop
if rs.deptno=10 then
update emp set sal=sal*1.1 where empno=rs.empno;
end if;
end loop;
end;

3.5 嵌套循环
例1:2层for循环
declare
result number;
begin
for i in 1..10 loop
for j in 1..10 loop
result:=i*j;
dbms_output.put_line(i||' * '||j||' = '||result);
end loop;
end loop;
end;

例2:乘法口诀表
declare
n_result number;
v_result varchar2(2);
begin
for i in 1..9 loop
for j in 1..i loop
n_result:=j*i;
if n_result<10 and j<>1 then
v_result:=n_result||' ';
else
v_result:=n_result;
end if;
dbms_output.put(j||'*'||i||'='||v_result||' ');
end loop;
dbms_output.put_line('');
end loop;
end;

4.退出循环
4.1 continue 退出本次循环(10G以上版本)
begin
for v_counter in 1..50 loop
if v_counter>20 and v_counter<=30 then
continue;
else
insert into temp_table values (v_counter,'for循环continue');
end if;
end loop;
end;

4.2 exit 退出本层循环
begin
for v_counter in 1..50 loop
if v_counter>10 then
exit;
else
insert into temp_table values (v_counter,'for循环exit');
end if;
end loop;
end;
嵌套循环和标号:通过在嵌套循环中使用标号,可以区分内层循环和外层循环,
并且可以在内层循环中直接退出外层循环
例3:
declare
n_result number;
begin
<<outer>>
for i in 1..10 loop
<<inter>>
for j in 1..10 loop
n_result:=i*j;
dbms_output.put_line('内层循环内输出:'||n_result);
-- exit inter when j=8;
-- exit outer when n_result=30;
end loop inter;
dbms_output.put_line('内、外层循环间输出:'||n_result);
end loop outer;
dbms_output.put_line('外层循环外输出:'||n_result);
end;

4.3 goto 用于跳转到特定标号处去执行语句.
declare
i int :=1;
begin
loop
insert into temp_table values(i,'loop循环+goto');
if i=10 then
goto end_loop;
end if;
i:=i+1;
end loop;
<<end_loop>>
dbms_output.put_line('循环结束');
end;

5.操纵数据
5.1使用VALUES子句插入数据
declare
v_deptno dept.deptno%type;
v_dname dept.dname%type;
begin
v_deptno:=&no;
v_dname:='&name';
insert into dept (deptno,dname) values(v_deptno,v_dname);
end;

5.2使用子查询插入数据
--复制表结构,不带数据
create table employee as select * from emp where 1=2;
--
declare
v_deptno emp.deptno%type:=&no;
begin
insert into employee select * from emp where deptno=v_deptno;
end;

5.3更新数据
使用表达式更新列值
declare
v_deptno dept.deptno%type:=&no;
v_loc dept.loc%type:='&loc';
begin
update dept set loc=v_loc where deptno=v_deptno;
end;

5.4使用子查询更新列值 MILLER
declare
v_ename emp.ename%type:='&name';
begin
update employee set (sal,comm) =
(select sal,comm from emp where ename=v_ename)
where job = (select job from emp where ename=v_ename)
end;

5.5删除数据
使用变量删除数据
declare
v_deptno dept.deptno%type:=&no;
begin
delete from dept where deptno=v_deptno;
end;

5.6使用子查询删除数据
declare
v_ename emp.ename%type:='&name';
begin
delete from employee where deptno=
(select deptno from emp where ename=v_ename);
end;

6.事务控制语句
事务控制语句包括commit,rollback以及savepoint等三种语句
例1:
declare
v_sal emp.sal%type:=&salary;
v_ename emp.ename%type:='&name';
begin
update emp set sal=v_sal where lower(ename)=v_ename;
select sal into v_sal from emp where ename=v_ename;
dbms_output.put_line(v_sal);
commit;
exception
when others then
--dbms_output.put_line('发生了运行时异常');
--raise_application_error(-20001,'发生了运行时异常');
rollback;
end;

例2:
declare
begin
insert into temp_table values(1,'事务控制语句');
savepoint a1;
insert into temp_table values(2,'事务控制语句');
savepoint a2;
insert into temp_table values(3,'事务控制语句');
savepoint a3;
rollback to a2;
commit;
end;