PLSQL

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 ,代表一个集合。
  1. 光标的属性:
    %isopen %rowcount 影响的行数(取走的行数)
    %found %notfound

  2. 一个会话中只能打开300个光标。too many cursor opened。
    conn sys/orcl@...:1521/orcl as sysdba
    show parameter cursor
    alter system set open_cursors=400;

  3. 上面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子程序体;

调用存储过程:

  1. 用sqlplus语句调用:
    exec sayHelloWorld();

  2. 在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

  1. 查询某个员工的所有信息:
    输出8个列

  2. 查询某个部门中的所有员工信息
    输出一个集合

  • 包:负责申明
    如果存储过程的输出参数是个集合,需要用到光标,那么需要先在包头中申明。

  • 包体:负责实现
    在包体中实现。


触发器trigger:
注册在表上的之前或之后执行特定语句(增删改)[for each row]的要触发的操作。

做日志:

语句级:
行级:

你可能感兴趣的:(PLSQL)