PLSQL: procedure Language/sql
是Oracle对sql语言的过程化扩展。支持sql语句。
打开输出开关:
set serveroutput on
declare
--说明部分,如不需要定义变量可不写。
定义变量、光标、例外
begin
--程序
程序包(API),查文档,看Oracle提供了哪些API。PL里最上面两本
dbms_output.put_line('');
exception
--例外处理语句
end;
/
查看程序包结构:
desc dbms_output;
- 变量:
基本数据类型:char,varchar2,date,number,boolean,long
married [constant] boolean :=true;
加 constant 常量。
引用型变量:
myname emp.ename%type
记录型变量(数组):
emprec emp%rowtype
记录型变量分量的引用(赋值):
emprec.ename:='hellen';
- if语句:
if ... then ...;
...
end if;
if ... then ...;
else ...;
end if;
if ... then ...;
elsif ... then ...;
else ...;
end if;
例子:判断用户从键盘输入的数字:
set serveroutput on;
accept num prompt '请输入';
declare
pnum number := #
begin
SYS.DBMS_OUTPUT.PUT_LINE(pnum);
end;
/
- 循环语句:
while 条件
loop
...
end loop;
loop
exit when 条件;
...
end loop;
for i in 1..3
loop
...
end loop;
输出数字1-10:
set serveroutput on;
declare
pnum number := #
begin
for i in 1..10
loop
SYS.DBMS_OUTPUT.PUT_LINE(i);
end loop;
end;
/
- 光标/游标 Cursor == ResultSet ,代表一个集合。
光标的属性:
%isopen %rowcount 影响的行数(取走的行数)
%found %notfound一个会话中只能打开300个光标。too many cursor opened。
conn sys/orcl@...:1521/orcl as sysdba
show parameter cursor
alter system set open_cursors=400;上面cursor的参数中cursor_sharing什么作用?性能优化非常有用!
exact、force(应急,短时间内性能提高)、similar
定义光标的语法:
cursor 光标名[变量名 数据类型,...]
is select ...;
declare
begin
打开光标:open c1;
loop
fetch c1 into pename,psal;
exit when c1%notfound;
dbms_output.put_line(pename+""+psal);
end loop;
关闭光标:close c1; //不关闭也没问题,浪费资源。
提交事务:commit; //默认读提交,如果不提交,cmd读不到。
end;
带参数的光标:
查询某个部门员工姓名:
declare
cursor c1(dno number) is select ename from emp where deptno=dno;
pename emp.ename%type;
begin
open c1(10);
loop
fetch c1 into pename;
exit when c1%notfound;
end loop;
commit;
end;
- 例外:
exception 相当于catch块:
exception
when zero_divide then
dbms_output.put_line('0不能做分母1');
dbms_output.put_line('0不能做分母2');
when value_error then
dbms_output.put_line('算数或转换错误');
when others then
dbms_output.put_line('其他例外');
自定义例外:
declare
no_data exception;
cursor c1(dno number) is select ename from emp where empno=dno;
begin
open c1(50);
fetch c1 into pename;
if c1%notfound then
raise no_data; //抛出例外
end if;
close c1;
exception
when no_data then
dbms_output.put_line('');
when others then
dbms_output.put_line('其他例外');
end;
例外是如何处理的?进程监视器:
pmon
当读进程和写进程出现意外,这个进程将会启动,处理意外发生后的后续操作。
- 需求分析:
sql语句
变量:初始值、最终怎么得到。
光标 退出条件
实例1:
统计每年入职的员工个数。
set SERVEROUTPUT ON
declare
cursor chiredate is select distinct to_char(hiredate,'yyyy') from emp order by 1;
phiredate varchar2(6);
num number;
total number(10) := 0;
begin
open chiredate;
loop
num := 0;
fetch chiredate into phiredate;
exit when chiredate%notfound;
select count(*) into num from emp where to_char(hiredate,'yyyy')=phiredate;
total := total + num;
dbms_output.put_line(phiredate||' '||num);
end loop;
close chiredate;
dbms_output.put_line('total '||total);
end;
/
实例2:
为员工涨工资。从最低工资调起每人长10%,但工资总额不能超过5万元,
请计算长工资的人数和长工资后的工资总额,并输出长工资人数及工资总额。
cursor csal is select sal from emp order by sal;
实例3:
实现按部门分段(6000以上、6000-3000、3000元以下)统计各工资段的职工人数、
以及各部门的工资总额。不包含奖金:
create table deptCount(
deptno number,
num1 number,
num2 number,
num3 number,
totalSal number
);
declare
cursor cdeptno is select deptno from dept;
pdeptno number;
cursor csal(dno number) is select sal from emp where deptno=dno;
psal number;
num1 number;num2 number;num3 number;
totalSal number;
begin
open cdeptno;
loop
num1 := 0;
num2 := 0;
num3 := 0;
totalSal := 0;
fetch cdeptno into pdeptno;
exit when cdeptno%notfound;
open csal(pdeptno);
loop
fetch csal into psal;
exit when csal%notfound;
totalSal:=totalSal+psal;
if psal < 3000 then num1:=num1+1;
elsif psal>=3000 and psal<6000 then num2:=num2+1;
else num3:=num3+1;
end if;
end loop;
close csal;
insert into deptCount values(pdeptno,num1,num2,num3,nvl(totalSal,0));
end loop;
close cdeptno;
commit;
end;
/
- 存储过程:
语法:命名规则:所有字母都大写用下划线分隔
create[or replace] procedure 过程名(参数列表)
as
plsql子程序体;
调用存储过程:
用sqlplus语句调用:
exec sayHelloWorld();在plsql中调用:
begin
sayHelloWorld();
end;
/
-
带参数的存储过程:一般不在存储过程或存储函数中做提交或回滚操作。
给指定员工涨100块钱,打印涨前和涨后的薪水:
create or replace procedure raisesalary(eno in number)
as
psal emp.sal%type;
begin
select sal into psal from emp where empno=eno;
--涨100:
update emp set sal=sal+100 where empno=eno;dbms_output.put_line('涨前:'||psal||'涨后:'||(psal+100));
end;
/
调用:
begin
raisesalary(7839);
commit;
end;
/
- 存储函数:必须要有return子句,用于返回函数值
create[or replace] function 函数名(参数列表)
return 函数值类型
as
plsql子程序体;
例子:查询某个员工年收入:
create or replace function queryincome(eno in number)
return number
as
psal ;
pcomm ;
begin
select sal,comm into psal,pcomm from emp where ;
return psal*12+nvl(comm,0);
end;
/
- 如果只有一个返回值,用存储函数,否则用存储过程。
查询某个员工的姓名、月薪、职位
- 用java程序调用存储过程:
CallableStatement extends PerparedStatement
jvm处理的是堆内存:
java -Xms100M -Xmx200M HelloWorld
查询某个员工的所有信息:
输出8个列查询某个部门中的所有员工信息
输出一个集合
包:负责申明
如果存储过程的输出参数是个集合,需要用到光标,那么需要先在包头中申明。包体:负责实现
在包体中实现。
触发器trigger:
注册在表上的之前或之后执行特定语句(增删改)[for each row]的要触发的操作。
做日志:
语句级:
行级: