1、简介
PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言
支持 SQL,在 PL/SQL 中可以使用:
数据操纵命令
事务控制命令
游标控制
SQL 函数和 SQL 运算符
PL/SQL 分为三个部分,声明部分、可执行部分和异常处理部分 大写是关键词 []可以省略
[DECLARE
Declarations 声明部分]
BEGIN
Plsql语句;
[EXCEPTION
handlers]
END;
--输出语句 ||拼接
dbms_output.put_line(内容);
2、标识符
使用标识符来为PL/SQL程序中的常量、变量、游标等命名。
标识符可以由字母、数字、美元符号($)、下划线(_)和数字符号(#)组成。以字母开头
如果有其它特殊字符要使用双引号括起来 最长不超过30个英文字母的长度
3、数据类型
PL/SQL数据类型不但支持Oracle SQL中的数据类型,还有自身自带的数据类型
(1)数值类型:
number(p,s):存放各种数字类型数据
pls_integer,binary_integer:数值类型,只能存放整数
(2)字符串类型:
varchar2(len):变长字符串类型,存放字符串类型数据
char(len):定长字符串类型
注:sql中的CHAR最大字节长度为2000字节,plsql中的CHAR最大字节长度为32767字节
sql中的VARCHAR2最大字节长度为4000字节,plsql中的VARCHAR2最大字节长度为32767字节
(3)日期类型:
date:日期类型
(4)%type类型
%type:它的类型是取数据库表中某一个字段的类型,作为变量类型
写法:
表名.列名%type; --完整的类型
emp.ename%type 等同于 varchar2(10)
--赋值 把数据库表中的值赋值给自定义的变量
--select 列名 into变量from 表名 where 条件表达式;
(5)record类型
普通的数据类型声名的变量,只能存放一个值,记录类型是存放一组值
它使用前需要去定义一个确定类型
1>记录类型的定义:
type type_name is record(
变量名 数据类型,
变量名 数据类型,
变量名 数据类型
);
type_name:记录类型名称
type emp_type is record(
ename varchar2(10),
job emp.job%type,
sal emp.sal%type
);
2>声名一个记录类型变量
变量名 记录类型;
v_emp emp_type;
3>给记录类型赋值
变量名称.属性名
v_emp.ename:='张三';
(6)%rowtype类型
%rowtype:它是%type类型和record类型的结合
变量名 表名%rowtype;
dept%rowtype;
v_dept dept%rowtype;
4、变量和常量
变量:它是存储数据的,它里面存放的值是可以根据程序需要改变的。
变量的声名语法:
变量名 数据类型 [NOT NULL] [:=默认值];
注: := 在plsql中是赋值符号
declare
v_n number(10):=1;
begin
v_n:=10;
end;
常量:它存储数据,一旦给它赋值,它的值就不可改变
常量名 constant 数据类型 :=默认值;
注:&:输入符号 从键盘输入
select * from emp where deptno=&deptno;
select * from emp where ename='&name';
declare
--声名一个number类型变量
v_m number(10);
begin
--从键盘输入一个数字存入变量v_m中
v_m:=&请输入一个数字;
--把变量v_m的值输出在控制台上
dbms_output.put_line('v_m的值是:'||v_m);
end;
二、pl流程控制语句
1、流程控制语句
可以控制程序执行的流程。条件语句 循环语句 顺序语句
2、条件控制
if语句
IF 语句根据条件执行一系列语句,有三种形式:
IF-THEN、 IF-THEN-ELSE 和 IF-THEN-ELSIF
1).if语句
语法:
if 条件表达式 then plsql语句; end if;
语义:如果条件表达式成立,那么执行then后面的plsql代码,如果条件不成立跳过if语句执行其它语句
如:
declare
--声名一个变量用来存放从键盘输入的值
v_str varchar2(20);
begin
--从键盘输入一个颜色字符串存入变量v_str
v_str:='&请输入一个颜色';
--判断输入的颜色是否为red,如果是red输出它是红色,如果不是输入其它颜色
if v_str='red' then
dbms_output.put_line('它是红色');
end if;
if v_str!='red' then
dbms_output.put_line('其它颜色');
end if;
end;
2).if else 语句
语法:
if 条件表达式 then plsql语句; else plsql语句; end if;
语义:如果if的条件表达式成立,执行then后面的代码,如果条件不成立执行else后面的代码;
如:
declare
--声名一个变量用来存放从键盘输入的值
v_str varchar2(20);
begin
--从键盘输入一个颜色字符串存入变量v_str
v_str:='&请输入一个颜色';
--判断输入的颜色是否为red,如果是red输出它是红色,如果不是输入其它颜色
if v_str='red' then
dbms_output.put_line('它是红色');
else
dbms_output.put_line('其它颜色');
end if;
end;
3)、elsif语句
语法:
if 条件表达式1 then plsql语句1; elsif 条件表达式2 then plsql语句2; ... elsif 条件表达式n then plsql语句n; else plsql语句; end if;
语义:如果条件表达式1成立,执行语句1,如果条件1不成立,判断第二个条件表达式,如果成立执行语句2,不成立判断下一条件,如果所有条件都不成立执行else后面的语句.其中elsif可以有多个,else部分可以省略
如:
--根据输入的字符串判断是什么动物
declare
--声名一个字符串变量保存输入的内容
v_str varchar2(20);
begin
--用变量v_str接收输入的数据
v_str:='&animal';
--如果是dog,输出它是一只狗
if v_str='dog' then
dbms_output.put_line('它是一只狗');
elsif v_str='cat' then
--如果是cat,输出它是一只猫
dbms_output.put_line('它是一只猫');
elsif v_str='pig' then
--如果是pig,输出它是一头猪
dbms_output.put_line('它是一头猪');
else
--输出其它生物
dbms_output.put_line('其它生物');
end if;
end;
4)、case语句
语法1:
case when 条件表达式1 then plsql命令 值1; when 条件表达式2 then 值2; when 条件表达式3 then 值3; ... else 默认值; end case;
语法2:
case 条件表达式 when 值1 then plsql语句1; when 值2 then plsql语句2; ... when 值n then plsql语句n; else plsql语句; end case;
语义:如果条件表达式的值,等于某个when后面的值,那么就执行相应then后面的plsql语句,如果表达式的值没在when所列的值中,那么执行else后面的语句,其中else部分可以省略。
如:
--根据输入的字符串判断是什么动物
declare
--声名一个字符串变量保存输入的内容
v_str varchar2(20);
begin
--用变量v_str接收输入的数据
v_str:='&animal';
--如果是dog,输出它是一只狗
case v_str
when 'dog' then
dbms_output.put_line('它是一只狗');
when 'cat' then
--如果是cat,输出它是一只猫
dbms_output.put_line('它是一只猫');
when 'pig' then
--如果是pig,输出它是一头猪
dbms_output.put_line('它是一头猪');
else
--输出其它生物
dbms_output.put_line('其它生物');
end case;
end;
3、循环控制
循环控制用于重复执行一系列语句
循环控制的三种类型:
LOOP - 无条件循环
WHILE - 根据条件循环
FOR - 循环固定的次数
loop循环
语法:
loop plsql语句; exit when 退出循环条件; 循环控制语句; end loop;
如:
--循环打印1到9的9个数字
declare
--声名一个变量,用来存放一个数字,(循环变量)
v_n number(10); --可以在此处赋值
begin
--给循环变量赋值为1
v_n:=1;
--循环语句
loop
--循环体执行的plsql语句
dbms_output.put_line(''||v_n);
--退出循环条件
exit when v_n=9;
--改变循环变量的值,保证循环不会死循环(循环控制语句)
v_n:=v_n+1;
end loop;
dbms_output.put_line('v_n='||v_n);
end;
exit when:退出循环关键字,如果条件成立立即退出循环
continue:退出本次循环,不会结束循环
return:退出程序,结束整个程序
while循环
语法:
while 循环条件 loop 循环体语句; 循环控制语句; end loop;
如:
--循环打印1到9
declare
--声名一个变量,来控制循环
v_n number(10);
begin
--给循环变量赋值
v_n:=1;
--while循环语句
while v_n <10 loop
--循环体语句(打印数字)
dbms_output.put_line(''||v_n);
--循环控制语句
v_n:=v_n+1;
end loop;
dbms_output.put_line('v_n='||v_n);
end;
for循环
语法:
for 循环变量 in [reverse] 集合|查询语句|游标变量 loop 循环体语句; end loop;
循环变量:不需要在declare中声明,变量类型根据in后面的集合或者查询语句而定,普通数据类型,record类型
reverse(一般不会用到):可选参数,表示循环的方向,不加表示从开始到结尾,加上表示从结尾到开头
数字类型集合写法
minValue .. maxValue 例如 1..10
如:
--循环打印1 到9
begin
--for循环语句
for i in 1..9 loop
--循环体语句
dbms_output.put_line(''||i);
end loop;
end;
for循环查询结果集
--循环打印dept表中的部门信息 begin --for循环语句,循环变量v_dept是一个记录类型,查询语句是*,dept%rowtype for v_dept in (select * from dept where deptno=&deptno) loop --循环体语句,打印部门信息 dbms_output.put_line(v_dept.deptno||','||v_dept.dname||','||v_dept.loc); end loop; end;
select into语句:
语法:
select 列名,列名,..,列名 into 变量1,变量2,..,变量n|record变量|rowtype变量 from 表名 where 条件;
注意:select into语句查询出的结果只能是一条数据,超过一条数据会报错;
--输入一个部门编号,打印这个部门的信息
declare --声名一个变量用来保存输入的部门编号 v_deptno number(10); --声名一个dept%rowtype类型的变量来保存一条部门信息 v_dept dept%rowtype; begin --接收从键盘输入的部门编号 v_deptno:=&deptno; --根据输入的部门编号查询出部门信息 select * into v_dept from dept where deptno=v_deptno; --打印部门信息 dbms_output.put_line(v_dept.deptno||','||v_dept.dname||','||v_dept.loc); end;
--输入一个部门编号,打印这个部门的信息
declare --声名一个变量用来保存输入的部门编号 v_deptno number(10); --声名一个变量用来保存部门编号 v_dno dept.deptno%type; --声名一个变量用来存放部门名称 v_dname dept.dname%type; --声名一个变量用来存放部门位置 v_loc dept.loc%type; begin --接收从键盘输入的部门编号 v_deptno:=&deptno; --根据输入的部门编号查询出部门信息 select deptno,dname,loc into v_dno,v_dname,v_loc from dept where deptno=v_deptno; --打印部门信息 dbms_output.put_line(v_dno||','||v_dname||','||v_loc); end;
4、顺序控制
顺序控制用于按顺序执行语句
顺序控制语句包括:
GOTO 语句 - 无条件地转到标签指定的语句
NULL 语句 - 什么也不做的空语句
goto语句
语法:
<> 循环执行的plsql语句; if 条件 then goto lable; end if;
<<>>:标签定义符
lable:标签名,符合标识符命名规范
goto语句:程序回到标签处执行
--循环打印1到9
declare v_n number(10):=1; begin <> dbms_output.put_line(''||v_n); v_n:=v_n+1; if v_n<10 then goto mylable; end if; end;
null语句
NULL: plsql中的空语句,它什么也不做,就是占位置
三、pl游标1、简介
游标逐行处理查询结果,以编程的方式访问数据
它实际上是一个指针,它在一段Oracle存放数据查询结果集或数据操作结果集的内存中(数据的缓存区),游标就是指向这个缓冲区的一个指针
2、游标类型
1),隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标,名字固定叫sql。
2),显式游标:显式游标用于处理返回多行的查询。
3),REF 游标:REF 游标用于处理运行时才能确定的动态 SQL 查询的结果
3、游标的属性
%found:返回一个布尔类型的值,如果游标指向的数据不为空,那么返回true,否则返回false
%notfound:和%found相反,指向的数据是空,返回true
%rowcount:它可以表示游标指向的缓冲区(结果集)的数据条数
%isopen:返回一个布尔类型的值,判断当前游标是否打开,如果是打开的返回true,否则返回false
注:boolean布尔类型:只有三个值,true,false,null
4、显示游标
显式游标在 PL/SQL 块的声明部分定义查询,该查询可以返回多行
显式游标,就是自己定义的游标
显式游标的使用:
(1)游标变量的声明
cursor 游标名 is select语句;
cursor cur_emp is select * from emp;
(2)打开游标
open 游标名称;
open cur_emp;
(3)fetch into 当前游标指向下一条数据并把数据保存在一个变量中
fetch 游标变量 into 变量
fetch cur_emp into v_emp;
(4)关闭游标
close 游标名称
close cur_emp;
如:
--使用游标打印所有员工信息 declare --声名一个游标变量,指向所有员工的信息select * from emp; cursor c_emp is select * from emp; --声名一个emp%rowtype类型的变量用来保存游标中的一条记录 v_emp emp%rowtype; begin --打开游标 open c_emp; --遍历游标 loop --fetch into游标指向下一条数据,并保存数据到变量v_emp中 fetch c_emp into v_emp; --判断游标是否还有数据,如果没有数据,就退出循环 exit when c_emp%notfound; --把这条员工信息打印出来 dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||v_emp.job||','||v_emp.sal||','||v_emp.deptno); end loop; --关闭游标 close c_emp; end;
--使用游标打印所有员工的信息
declare --声名一个游标变量指向所有员工的集合 cursor c_emp is select * from emp; --声名一个变量用来保存游标的一条记录 v_emp emp%rowtype; begin --打开游标 open c_emp; --执行一次fetch into 让游标指向第一条数据 fetch c_emp into v_emp; --while循环,条件是循环条件 while c_emp%found loop --打印员工信息 dbms_output.put_line(v_emp.ename||','||v_emp.job||','||v_emp.sal||','||v_emp.deptno); --fetch into将游标指向下一条数据 fetch c_emp into v_emp; end loop; dbms_output.put_line(c_emp%rowcount||''); --关闭游标 close c_emp; end;
for循环会自动打开游标、关闭游标,并且自动会让游标指向一条记录
--使用游标打印所有员工的信息
declare --声名一个游标变量指向所有员工的集合 cursor c_emp is select * from emp; begin for v_emp in c_emp loop --打印员工信息 dbms_output.put_line(v_emp.ename||','||v_emp.job||','||v_emp.sal||','||v_emp.deptno||','||c_emp%rowcount); end loop; end;
带参数的显式游标
声明显式游标时可以带参数以提高灵活性
语法:
cursor 游标名(参数名 数据类型,参数名 数据类型,...) is select 语句;
使用 :open 游标名(参数,参数..);
declare --声名一个游标,输入一个部门编号,打印该部门的员工信息 cursor c_emp(v_dno emp.deptno%type) is select * from emp where deptno=v_dno; --声名一个rowtype类型变量保存游标中的一条记录 v_emp emp%rowtype; begin --打开游标 open c_emp(10); loop --fetch into fetch c_emp into v_emp; --判断游标当前数据是否为空,如果为空退出循环 exit when c_emp%notfound; --打印员工信息 dbms_output.put_line(v_emp.ename||','||v_emp.job||','||v_emp.sal||','||v_emp.deptno); end loop; --关闭游标 close c_emp; end;
declare cursor c(dno number) is select * from emp where deptno=dno; begin for x in c(&dno) loop dbms_output.put_line(x.ename); dbms_output.put_line(c%rowcount); end loop; --for 自动关闭 for循环结束之后 end loop; end;
使用显式游标更新行
允许使用游标删除或更新活动集中的行
声明游标时必须使用 SELECt … FOR UPDATE语句
declare v_emp emp%rowtype; cursor mycursor is select * from emp where empno = 7369 for update; begin open mycursor; fetch mycursor into v_emp; while mycursor%found loop --where current of游标名; 对游标读取的所在行进行更新和删除 update emp set ename = 'tom' where current of mycursor; fetch mycursor into v_emp; end loop; close mycursor; end;
5.隐式游标
在PL/SQL中使用DML语句时自动创建隐式游标
隐式游标自动声明、打开和关闭,其名为 SQL
通过检查隐式游标的属性可以获得最近执行的DML 语句的信息
隐式游标的属性有:
%FOUND – SQL 语句影响了一行或多行时为 TRUE
%NOTFOUND – SQL 语句没有影响任何行时为TRUE
%ROWCOUNT – SQL 语句影响的行数
%ISOPEN - 游标是否打开,始终为FALSE
如:
declare
v_emp emp%rowtype;
begin
update emp set comm=100 where deptno=&deptno;
dbms_output.put_line('修改的数据条数:'||sql%rowcount);
if sql%found then
dbms_output.put_line('aaaaaaaaaaaaaaa');
end if;
delete from emp where deptno=&dno;
dbms_output.put_line('删除了'||sql%rowcount||'条数据');
end;
6.REF游标
REF 游标和游标变量用于处理运行时动态执行的 SQL 查询
创建游标变量需要两个步骤:
1.声明 REF 游标类型
语法:
type 类型名称 is ref cursor;
2.声明 REF 游标类型的变量
语法 变量名称 游标变量类型;
使用: open 游标变量 for select 语句;
如:
--查询所有的员工信息 declare --声明 REF 游标类型 type c_type is ref cursor; --声名REF游标类型变量 cur c_type; --声名一个变量保存emp表的信息 v_emp emp%rowtype; begin open cur for select * from emp; loop fetch cur into v_emp; exit when cur%notfound; dbms_output.put_line(v_emp.ename); end loop; close cur; end;四、集合类型
1、集合类型
集合(collection):它是存放一组数据类型相同的数据,是相同类型元素的组合
集合数据类型分类:
1).索引表(index by tables):或者叫做关联数组(associative arrays)
2).嵌套表(nested table)
3).可变长度数组(varray:variable-size arrays)
2、集合的属性和方法
集合名字.属性名 集合名字.方法名
1).first取集合的第一个元素的下标
2).last取集合的最后一个元素的下标
3).count 取集合的总长度
4).limit 取集合元素下标的最大值 (索引表和嵌套表是不限个数的,所以返回null,变长数组返回定义时的最大索引 )
5).delete([n]) 删除集合中的元素,加n表示下标,删除对应下标的值
6).extend(n[,ind]):扩展集合元素 n是一个数字,表示扩展的元素个数,ind是集合中的一个元素的下标,加上它表示扩展集合时,给扩展的元素加上值,值是ind这个下标对应的元素
7).next(下标)取当前元素下一个元素的下标
8).prior(下标)取当前元素上一个元素的下标
3、索引表
使用整数(可为负)(pls_integer,binary_integer)或字符串来作为下标,下标可以不连续;元素个数无限制,只能用在PLSQL中,不可以存储在数据库中.
定义索引表类型的语法:
--1声明索引表类型
type 类型名称 is table of 数据类型(是集合中值的数据类型)index by 下标的数据类型(varchar2,pls_integer,binary_integer);
type mytype is table of varchar2(200) index by pls_integer;
--2声名一个集合变量
变量名 类型名
v mytype;
集合中数据的存取:
集合变量(下标)
v(下标);
v(下标):=值;
declare --声名一个索引表类型 type mytype is table of varchar2(200) index by binary_integer; --声名一个索引表类型变量 tab mytype; --声名一个变量保存索引表的下标 ind varchar2(20); begin tab(1):='张三'; tab(-2):='李四'; tab(0):='王五'; ind:=tab.first; ---遍历集合 loop --打印集合元素 dbms_output.put_line(tab(ind)); --退出条件 exit when ind=tab.last; ind:=tab.next(ind); end loop; end;
declare --声名记录类型 type recType is record( name varchar2(30), sex varchar2(3) ); --声名一个索引表类型 type indType is table of recType index by pls_integer; --声名一个变量 ind indType; --声名一个记录类型变量 rec recType; --声名一个记录类型变量 rec2 recType; begin --给记录类型赋值 rec.name:='张三'; rec.sex:='男'; --给集合中添加一个元素 ind(1):=rec; --取集合中的值 rec2:=ind(1);---取出来的是一个记录类型数据 dbms_output.put_line(rec2.name||','||rec2.sex); end;
4、嵌套表
使用整数(只能为正)作为下标,下标是连续的;元素个数无限制的,可以用在PLSQL中,也可以存储在数据库中
定义嵌套表类型:
type 类型名称 is table of 数据类型(存储的数据的数据类型);
变量声名:
变量名 类型名称
数据的存取和索引表相同
嵌套表在赋值之前需要初始化
嵌套表的初始化:
变量名:=类型名(); --初始化
变量名:=类型名(值,值,值);
declare
--声名一个嵌套表类型,存放字符串数据
type tabType is table of varchar2(200);
--声名变量
tab1 tabType;
tab2 tabType;
--声名一个变量保存嵌套表的下标
ind pls_integer;
begin
--初始化嵌套表
tab1:=tabType();
--打印嵌套表tab1的长度
dbms_output.put_line('tab1的长度'||tab1.count);
--初始化嵌套表tab2
tab2:=tabType('a','b','c','d');
--打印嵌套表tab2的长度
dbms_output.put_line('tab2的长度'||tab2.count);
---遍历集合
ind := 1;
loop
--打印集合元素
dbms_output.put_line(tab2(ind));
--退出条件
exit when ind=tab2.last;
ind:=tab2.next(ind);
end loop;
for i in tab2.first..tab2.last loop
dbms_output.put_line(tab2(i));
end loop;
end;
嵌套表在数据库中的使用:
create type 类型名称 is table of 数据类型;
create type tabType is table of varchar2(30);
declare
--声名一个tabType类型的嵌套表变量
v_tab tabType;
begin
--初始化
v_tab:=tabType('1','2','3');
--遍历
for i in v_tab.first..v_tab.last loop
dbms_output.put_line(v_tab(i));
end loop;
end;
建表时使用嵌套表类型
create table 表名(
列 数据类型,
自定义列名 嵌套表类型
)nested table 嵌套表类型列名 store as 表名(是数据库中没有的表);
create table tab( deptno number(10), namelist tabType )nested table namelist store as emp_names;
insert into tab(deptno,namelist) values(10,
嵌套表类型 ('SMITH','JSON','EDISION'));
insert into tab(deptno,namelist) values(20,tabType('SMI','SON','SION'));
select * from tab;
select * from table(select namelist from tab where deptno=20);
先创建嵌套表类型再建表
删除:先删除表,再删除嵌套表类型
Drop type 类型名字;
5、变长数组
使用整数(只能为正)(pls_integer,binary_integer)作为下标,下标是连续的;元素个数有限制的,可以用在PLSQL中,也可以存储在数据库中
变长数组类型的声明
type 类型名称 is varray|varying array(长度) of 数据类型(保存的数据的数据类型);
变量名 类型名;
使用和嵌套表一样,使用前需要初始化
变量:=类型();
变量:=类型(值,值,值,值,值);
declare
--声名一个变长数组类型
type arrType is varray(10) of varchar2(20);
--声名一个数组变量
arr arrType;
begin
--初始化
arr:=arrType('a','b','c');
--打印数组的长度
dbms_output.put_line('数组的长度'||arr.count);
arr.extend(7);
--打印数组的长度
dbms_output.put_line('数组的长度'||arr.count);
end;
变长数组在数据库中的使用;
create type 类型名称 is varray|varying array(长度) of 数据类型;
create table 表名(
列名 数据类型,
数组列 数组类型
);
insert into 表名(列名,数组列名) values(值,数组类型(值,值,值));
select * from table(select 数组列 from 表名 where 条件);
6、bulk collect
bulk collect:可以把一组数据取出来存入一个集合类型变量中
select ... into 变量:只能查出一条数据保存到变量中
select ... bulk collect into 集合类型变量:可以查出多条数据存入一个变量中
--查询所有员工的名字
declare --声名一个集合类型 type tabType is table of emp.ename%type; --声名一个嵌套表变量 namelist tabType; begin --注意:这里是不需要初始化集合变量 namelist:=tabType(); select ename bulk collect into namelist from emp; --打印员工姓名 for i in namelist.first..namelist.last loop dbms_output.put_line(namelist(i)); end loop; end;
fetch 游标 bulk collect into 集合类型变量;
-- 查询员工的信息
declare --声名一个游标变量 cursor cur is select * from emp; --声名一个集合类型 type tabType is table of emp%rowtype; --声名一个变量 emplist tabType; begin --打开游标 open cur; fetch cur bulk collect into emplist; --关闭游标 close cur; for i in emplist.first..emplist.last loop dbms_output.put_line(emplist(i).ename); end loop; end;
7、批量绑定
forall 变量 in 集合
sql语句;--增insert、删delete、改update
--根据部门编号删除部门下的员工
declare begin for v_dept in (select * from dept) loop delete from emp where deptno=v_dept.deptno; end loop; end;
declare --声名一个集合类型 type tabType is table of dept.deptno%type; --声名一个变量 dno tabType; begin --将所有的部门编号放入dno中 select deptno bulk collect into dno from dept; forall i in dno.first..dno.last delete from emp where deptno=dno(i); end;



