PL/SQL基础

1. 概述

1.1 SQL Developer安装

见安装文件

1.2 PL/SQL的作用和第一个PL/SQL程序

-- 给员工涨工资
	-- 总裁涨1000
	-- 经理涨800
	-- 其他员工涨400
	
plsql的作用:
	操作oracle数据库效率最高
	为后面存储过程打基础

-- 打印 hello world
declare 
	-- 说明部分(变量,光标或者例外)
begin 
	-- 程序体
	dbms_output.put_line(‘Hello World‘);
end;

-- 打开输出开关
set serveroutput on

1.3 PL/SQL简介

PL/SQL(Procedure Language SQL)

PL/SQL是Oracle对sql语言的过程化扩展
	指在SQL命令语言中增加了过程处理语句(如分支、循环等),使SQL语言具有过程处理能力。
	面向过程
	
不同数据库的SQL扩展
Oracle :PL/SQL
DB2:SQL/PL
SQL Server: Transac-SQL(T-SQL)

2. PL/SQL基础语法

2.1 PL/SQL基本变量类型

-- PL/SQL的程序结构

declare 
	-- 说明部分(变量说明,光标声明或者例外说明)
begin 
	-- 语句序列(DML语句)
exception
	-- 例外处理语句
end;


-- 说明部分
-- 定义基本变量
类型:char  varchar2  date  number  boolean  long
举例:
	var1 char(15);
	married boolean := true;
	psal number(7,2);


declare
    pnumber number(7,2);
   pname varchar(20);
   pdate date;
begin 
    pnumber:=1;
    DBMS_OUTPUT.put_line(pnumber);
    pname:=‘Tom‘;
    DBMS_OUTPUT.put_line(pname);
    pdate:=sysdate;
    DBMS_OUTPUT.put_line(pdate);
    --计算明天的日期
    DBMS_OUTPUT.put_line(pdate+1);
end;   

2.2 PL/SQL引用型变量和记录型变量

-- 引用型变量
-- 举例
	my_name emp.ename%type;
	
set serveroutput on
declare
    -- 定义引用型变量,查询并打印7839的项目和薪水
    -- pname varchar2(20);
    -- psal number;
    pname emp.ename%type;
    psal emp.sal%type;
begin 
    --得到7839的姓名和薪水
    select ename,sal into pname,psal from emp where empno=7839;
    -- 打印姓名和薪水
    dbms_output.put_line(pname||‘的薪水是‘||psal);
end;

-- 记录型变量
-- 举例
	emp_rec emp%rowtype;	
-- 记录型变量分量的引用
	emp_rec.ename := ‘ADAMS‘;
	
set serveroutput on
declare
    -- 定义记录型变量,查询并打印7839的项目和薪水
   emp_rec emp%rowtype;
begin 
    --得到7839的姓名和薪水
    select * into emp_rec  from emp where empno=7839;
    -- 打印姓名和薪水
    dbms_output.put_line(emp_rec.ename||‘的薪水是‘||emp_rec.sal);
end;

2.3 PL/SQL中if语句的使用

1.	IF 条件 THEN 语句1;
	语句2;
	END IF;
	
2.	IF 条件 THEN 语句序列1;
	ELSE 语句序列2;
	END IF;
	
3.	IF 条件 THEN 语句;
	ELSIF 语句 THEN 语句;
	ELSE 语句;
	END IF;
	
-- 判断用户从键盘输入的数字
set serveroutput on

accept num prompt ‘请输入一个数字‘;
declare
   pnum number :=#
begin 
   if pnum=0 then dbms_output.put_line(‘你输入的数字是0‘);
   elsif pnum=1 then dbms_output.put_line(‘你输入的数字是1‘);
   elsif pnum=2 then dbms_output.put_line(‘你输入的数字是2‘);
   elsif pnum=3 then dbms_output.put_line(‘你输入的数字是3‘);
   elsif pnum=4 then dbms_output.put_line(‘你输入的数字是4‘);
   elsif pnum=5 then dbms_output.put_line(‘你输入的数字是5‘);
   elsif pnum=6 then dbms_output.put_line(‘你输入的数字是6‘);
   elsif pnum=7 then dbms_output.put_line(‘你输入的数字是7‘);
   elsif pnum=8 then dbms_output.put_line(‘你输入的数字是8‘);
   elsif pnum=9 then dbms_output.put_line(‘你输入的数字是9‘);
   else dbms_output.put_line(‘你输入的为其他数字‘);
   end if;
end;

2.4 PL/SQL循环语句的使用

1.	WHILE total<=25000 LOOP
 	...
 	total := total+salary;
 	END LOOP;
 
 eq:
 set serveroutput on
declare
   pnum number :=1;
begin 
  while pnum <=10 loop
    dbms_output.put_line(pnum);
    pnum := pnum+1;
    end loop;
end;
 
 
 
 2.		Loop 
 		EXIT [ WHEN 条件 ];
 			...
 		End loop;
 -- 推荐使用这种循环
 
 eq:
 set serveroutput on
declare
   pnum number :=1;
begin 
  loop 
    exit when pnum>10;
    dbms_output.put_line(pnum);
    pnum:=pnum+1;
  end loop;
end;


3.		FOR I IN 1..3 LOOP
		语句序列;
		END LOOP;
		


eq:
set serveroutput on
declare
   pnum number:=1;
begin 
  for pnum in 1..10 loop
    dbms_output.put_line(pnum);
  end loop;
end;

3. 光标(游标)

3.1 PL/SQL光标之光标的引入

-- 给员工涨工资
	-- 总裁涨1000
	-- 经理涨800
	-- 其他员工涨400
set serveroutput on
declare
   ptilte varchar(20);
begin 
  select job into ptilte from emp;
  if ptilte =‘PRESIDENT‘ then update emp set sal=sal + 1000;
  elsif ptilte =‘MANAGER‘ then update emp set sal=sal + 800;
  else update emp set sal=sal + 400;
  end if;
end;   -- error

光标
就是一个结果集(Result Set)

3.2 PL/SQL光标之光标的语法和第一个实例

-- 光标的语法
CURSOR 光标名 [(参数名 数据类型 [,参数名 数据类型] ... )]
IS SELECT 语句;

-- 一个具体的光标
cursor c1 is select ename from emp;

-- 从光标中取值
-- 打开光标 执行查询
open c1;
-- 关闭光标 释放资源
close c1;
-- 取一行光标的值
fetch c1 into pename;
fetch 的作用:
	把当前指针指向的记录返回
	将指针指向下一条记录

--光标的属性
%found  
%notfound


-- 使用光标查询员工姓名和工资,并打印
set serveroutput on
declare
  cursor cemp is select ename,sal from emp;
  pename emp.ename%type;
  psal emp.sal%type;
begin 
  open cemp;
  loop 
    fetch cemp into pename,psal;
  exit when cemp%notfound;
    dbms_output.put_line(pename||‘的薪水是‘||psal); 
  end loop;
  close cemp;
end;

3.3 实例:给员工涨工资

-- 给员工涨工资
	-- 总裁涨1000
	-- 经理涨800
	-- 其他员工涨400
	
set serveroutput on
declare
  cursor cemp is select empno,empjob from emp;
  pempno emp.empno%type;
  pjob emp.empjob%type;
  
begin 
	rollback;
  open cemp;
  
  loop 
    fetch cemp into pempno,pjob;
  exit when cemp%notfound;
    if pjob=‘PRESIDENT‘ then update emp set sal =sal+1000;
        elsif pjob=‘MANAMGR‘ then update emp set sal =sal+800;
        else update emp set sal =sal+400;
    end if;
    
  end loop;

  close cemp;
  -- 对于oracle,默认的事务隔离级别是 read committed
  commit; -- 事务提交
  dbms_output.put_line(‘涨工资完成‘); 
end;

3.4 PL/SQL光标之光标的属性和光标数的限制

--光标的属性
%found   -- true false
%notfound
%isopen -- 判断光标是否打开 打开为true 否则为false
%rowcount -- 影响的行数

-- 光标数的限制
默认情况下,oracle数据库只允许在同一个会话中,打开300个光标
show parameter cursor
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cursor_sharing                       string      EXACT
cursor_space_for_time                boolean     FALSE
open_cursors                         integer     300
session_cached_cursors               integer     50

修改光标数的限制
alter system set open_cursors =400 scope=both;
scope的取值:
	both
	menory
	spfile(数据库需要重启)

-- eq
set serveroutput on
declare
  cursor cemp is select empno,empjob from emp;
  pempno emp.empno%type;
  pjob emp.empjob%type;
  
begin 

  open cemp;
  if cemp%isopen then
    dbms_output.put_line(‘光标已经打开‘); 
  else 
    dbms_output.put_line(‘光标没有打开‘); 
  end if;
  loop 
    fetch cemp into pempno,pjob;
  exit when cemp%notfound;
   dbms_output.put_line(‘rowcount:‘||cemp%rowcount); 
  end loop;
  close cemp;
  
end;


3.5 PL/SQL光标之带参数的光标

CURSOR 光标名 [(参数名 数据类型 [,参数名 数据类型] ... )]
IS SELECT 语句;


-- 查询某个部门中员工的姓名
set serveroutput on
declare
  cursor cemp(dno number) is select ename from emp where deptno=dno;
  pename emp.ename%type;
begin 
  open cemp(10);
  loop 
    fetch cemp into pename;
  exit when cemp%notfound;
   dbms_output.put_line(pename); 
  end loop;
  close cemp; 
end;

4. 例外(异常)

4.1 例外的概念和系统例外

例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性
系统例外
	no_data_found	没有找到数据
	too_many_rows    select...into语句匹配多个行
	zero_divide		被零除
	value_error		算术或装换错误
	timeout_on_resource		在等待资源时发生超时
自定义例外

4.2 系统例外之no_data_found

-- 没有找到数据

set  serverout on
declare
    pename emp.ename%TYPE;
begin
	-- 查询员工号是1234的员工姓名
    select ename into pename from emp where empno=1234;
    
    exception 
        when no_data_found then DBMS_OUTPUT.PUT_LINE(‘没有找到该员工‘);
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/

4.3 系统例外之too_many_rows

-- select...into语句匹配多个行

set  serverout on
declare
    pename emp.ename%TYPE;
begin
    -- 查询所有10号部门的员工姓名
    select ename into pename from emp where deptno=10;
    
    exception 
        when too_many_rows then DBMS_OUTPUT.PUT_LINE(‘select...into语句匹配多个行‘);
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/

4.4 系统例外之zero_divide

-- 被零除

set  serverout on
declare
    pnum number;
begin
    pnum:=1/0;
    
    exception 
        when zero_divide then DBMS_OUTPUT.PUT_LINE(‘0不能做除数‘); 
                                DBMS_OUTPUT.PUT_LINE(‘被零除‘);
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/

4.5 系统例外之value_error

-- 算术或转换错误

set  serverout on
declare
    pnum number;
begin
    pnum:=‘abc‘;
    
    exception 
        when value_error then DBMS_OUTPUT.PUT_LINE(‘算术或转换错误‘); 
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/

4.6 自定义例外

定义变量,类型是exception
使用raise 抛出自定义例外

-- 查询50号部门的员工姓名
set  serverout on
declare
    cursor cemp is select ename  from emp where  deptno=50;
    pename emp.ename%type;
    no_emp_found exception;
begin
  open cemp;
    fetch cemp into pename;
    if cemp%notfound then raise no_emp_found;
    end if;
 close cemp;
    exception 
        when no_emp_found then DBMS_OUTPUT.PUT_LINE(‘没有找到员工‘); 
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘); 
end;
/

5. 案例集锦

5.1 运用瀑布模型完成PLSQL程序的设计

需求分析
	设计(1.概要设计   2. 详细设计)
			编码(codeing)
					测试 (testing)
						上线
						

SQL语句
变量:1.初始值是多少
	2.最终值如何得到

5.2 案例:统计每年入职的员工人数

SQL语句:
select to_char(hiredate,‘yyyy‘) from emp;
-> 光标-> 循环-> 退出条件:notfound
变量: 初始值   最终值如何得到
每年入职的员工人数
count80 number:=0;
count81 number:=0;
count82 number:=0;
count87 number:=0;

----------------------------------------------------------------------------------------

set  serverout on
declare
    cursor cemp is select to_char(hiredate,‘yyyy‘)  from emp;
    phiredate varchar2(4);
    count80 number:=0;
    count81 number:=0;
    count82 number:=0;
    count87 number:=0;
begin
  open cemp;
    loop
        fetch cemp into phiredate;
        exit when cemp%notfound ;
        if phiredate=‘1980‘  then count80:=count80+1;
        elsif phiredate=‘1981‘  then count81:=count81+1;
        elsif phiredate=‘1982‘  then count82:=count82+1;
        else count87:=count87+1;
        end if;
    end loop;
 close cemp;
 DBMS_OUTPUT.PUT_LINE(‘Total:‘||(count80+count81+count82+count87)); 
 DBMS_OUTPUT.PUT_LINE(‘count80:‘||count80); 
 DBMS_OUTPUT.PUT_LINE(‘count81:‘||count81); 
 DBMS_OUTPUT.PUT_LINE(‘count82:‘||count82); 
 DBMS_OUTPUT.PUT_LINE(‘count87:‘||count87); 
    exception 
        when no_data_found then DBMS_OUTPUT.PUT_LINE(‘没有找到员工‘); 
        when others then DBMS_OUTPUT.PUT_LINE(‘其他例外‘); 
end;
/

5.3 案例:员工涨工资问题

为员工涨工资。从最低工资涨起每人涨10%,但工资总额不能超过5万元,请计算涨工资的人数和涨工资后的工资总额,并输入涨工资人数及工资总额。

SQL语句
select empno,sal from emp order by sal ;
-> 光标-> 循环-> 退出条件:1.工资总额>5W   2. %notfound

变量: 初始值   最终值如何得到
涨工资的人数
countEmp number:=0;
涨后的工资总额:
	salTotal number;
	1.select sum(sal) into salTotal from emp;
	2.涨后的工资总额=涨前的工资总额+sal*0.1;
	
-----------------------------------------------------------------------------------------------------------------
set  serverout on
declare
    cursor cemp is select  empno,sal  from emp order by sal;
    pempno emp.empno%type;
    psal emp.sal%type;
    
    countEmp number :=0;
    salTotal number;
    
begin
    select sum(sal) into salTotal from emp;
  open cemp;
    loop
        exit when salTotal>50000; 
        	fetch cemp into pempno,psal;
        exit when cemp%notfound; 
        	update emp set sal=sal*1.1 where empno=pempno;
        	countEmp:=countemp+1;
        	salTotal:=salTotal +psal*0.1;
    end loop;
 close cemp;
 commit;
 	DBMS_OUTPUT.PUT_LINE(‘人数:‘||countEmp); 
 	DBMS_OUTPUT.PUT_LINE(‘salTotal: ‘||salTotal); 
end;
/

5.4 案例:涉及两张表的员工涨工资问题

按部门分段(6000以上、(6000,3000)、3000元以下)统计各工资段的职工人数、以及各部门的工资总额(工资总额中不包括奖金)


SQL语句
1.有哪些部门
select deptno  from dept;
--> 光标-> 循环-> 退出条件:%notfound
2.部门中员工的薪水
select sal from emp where deptno=?  
--> 带一个参数的光标-> 循环-> 退出条件:%notfound
变量: 初始值   最终值如何得到
每个段的员工人数
count1 number;
count2 number;
count3 number;
每个部门的工资总额:
saltotal number;
	1.select sum(sal) into saltotal from emp where deptno=???
	2.累加
	

----------------------------------------------------------------------------------
create table msg(deptno number,count1 number,count2 number,count3 number,saltotal number);

set  serverout on
declare
   cursor cdept is select deptno from dept;
    pdeptno dept.deptno%type;
    cursor cemp(dno number) is select sal from emp where deptno =dno;
    psal emp.sal%TYPE;
    count1 number;
    count2 number;
    count3 number;
    saltotal number;
begin
   open cdept;
    loop
        fetch cdept into pdeptno;
        exit when cdept%notfound;
        count1:=0;count2:=0;count3:=0;
        select sum(sal) into saltotal from emp where deptno=pdeptno;
        open cemp(pdeptno);
            loop
                fetch cemp into psal;
                exit when cemp%notfound;
                    if psal <3000 then count1:=count1+1;
                        elsif psal>=3000 and psal <6000 then count2:=count2+1;
                        else count3:=count3+1;
                    end if;
            end loop;
        close cemp;
     insert into msg values(pdeptno,count1,count2,count3,nvl(saltotal,0));
     
    end loop;
    
    
   close cdept;
   commit;
 DBMS_OUTPUT.PUT_LINE(‘统计完成‘); 
end;
/

PL/SQL基础

上一篇:aFleX自定义脚本技术介绍


下一篇:py-faster-rcnn几个辅助脚本