Oracle——PL/SQL

什么是PL/SQL

PL/SQL是一种过程化SQL语言(Procedural Language/SQL)。PL/SQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL就是把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断、循环等操作实现复杂的功能或者计算的程序语言。

PL/SQL语法

1)hello,world

--打印Hello World

declare
  --说明部分
begin
  --程序部分
  dbms_output.put_line(‘Hello World‘);  -- dbms_output相当于java中的类
end;
/

2)定义变量类型

  • 引用型变量
--引用型变量: 查询并打印7839的姓名和薪水

declare
  --定义变量保存姓名和薪水
  --pename varchar2(20);	-- 声明变量类型的方式1:直接定义变量的类型
  --psal   number;
  pename emp.ename%type;	-- 声明变量类型的方式2(引用型变量):与emp表中的ename列的类型相同
  psal   emp.sal%type;
begin
  --得到7839的姓名和薪水
  select ename,sal into pename,psal from emp where empno=7839;	-- 使用into为变量赋值

  --打印
  dbms_output.put_line(pename||‘的薪水是‘||psal);	-- ||是Oracle中的字符串拼接
end;
/
  • 记录型变量
--记录型变量: 查询并打印7839的姓名和薪水

declare
  --定义记录型变量:代表emp表中的一行
  emp_rec emp%rowtype;
begin
  select * into emp_rec from emp where empno=7839;

  dbms_output.put_line(emp_rec.ename||‘的薪水是‘||emp_rec.sal);
end;
/

3)if语句

-- 判断用户从键盘输入的数字

--接受键盘输入
--变量num:是一个地址值,在该地址上保存了输入的值
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‘);
     else dbms_output.put_line(‘其他数字‘);
  end if;
end;
/

4)循环

-- 打印1~10
declare
  -- 定义变量
  pnum number := 1;
begin
  loop
    --退出条件
    exit when pnum > 10;

    --打印
    dbms_output.put_line(pnum);
    --加一
    pnum := pnum + 1;
  end loop;
end;
/

5)光标

-- 查询并打印员工的姓名和薪水
/*
光标的属性: %isopen(是否打开)   %rowcount(影响的行数)
             %found(是否有值)    %notfound(是否无值)

*/
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 没有取到记录;
       exit when cemp%notfound;

       dbms_output.put_line(pename||‘的薪水是‘||psal);
  end loop;

  --关闭光标
  close cemp;
end;
/

示例:给员工涨工资

-- 给员工涨工资,总裁1000 经理800 其他400
declare
  --定义光标
  cursor cemp is select empno,job from emp;
  pempno emp.empno%type;
  pjob   emp.job%type;
begin

  --打开光标
  open cemp;
  loop
       --取一个员工
       fetch cemp into pempno,pjob;
       exit when cemp%notfound;

       --判断职位
       if pjob = ‘PRESIDENT‘ then update emp set sal=sal+1000 where empno=pempno;
          elsif pjob = ‘MANAGER‘ then update emp set sal=sal+800 where empno=pempno;
          else update emp set sal=sal+400 where empno=pempno;
       end if;

  end loop;
  --关闭光标
  close cemp;

  --提交  ----> why?: 事务 ACID
  commit;

  dbms_output.put_line(‘完成‘);
end;
/
  • 带参数的光标
-- 查询某个部门的员工姓名
declare
   --形参
   cursor cemp(dno number) is select ename from emp where deptno=dno;
   pename emp.ename%type;
begin
   --实参
   open cemp(20);
   loop
        fetch cemp into pename;
        exit when cemp%notfound;

        dbms_output.put_line(pename);

   end loop;
   close cemp;
end;
/

6)例外(异常)

  • 系统例外
-- 被0除
declare
   pnum number;
begin
  pnum := 1/0;

exception
  when zero_divide then dbms_output.put_line(‘1:0不能做分母‘);
                        dbms_output.put_line(‘2:0不能做分母‘);
  when value_error then dbms_output.put_line(‘算术或者转换错误‘);
  when others then dbms_output.put_line(‘其他例外‘);
end;
/
  • 自定义例外
-- 查询50号部门(50号部门不存在)的员工
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
    raise no_emp_found;
  end if;

  --进程:pmon进程(proccesss monitor)
  close cemp;

exception
  when no_emp_found then dbms_output.put_line(‘没有找到员工‘);
  when others then dbms_output.put_line(‘其他例外‘);
end;
/

实例1:统计每年入职的员工个数(使用PL/SQL)

/*
1、SQL语句
select to_char(hiredate,‘yyyy‘) from emp;
---> 集合 ---> 光标 ---> 循环---> 退出: notfound

2、变量:(*)初始值  (*)最终如何得到
每年入职的人数
count80 number := 0;
count81 number := 0;
count82 number := 0;
count87 number := 0;
*/
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(‘1980:‘|| count80);
  dbms_output.put_line(‘1981:‘|| count81);
  dbms_output.put_line(‘1982:‘|| count82);
  dbms_output.put_line(‘1987:‘|| count87);
end;
/

实例2:为员工涨工资,总工资最低的人开始涨,没人涨10%,但工资总额不超过万元,请计算长工资的人数和长工资后的工资总额。

/*
1、SQL语句
selet empno,sal from emp order by sal;
---> 光标  ---> 循环  ---> 退出:1. 总额>5w   2. notfound

2、变量:(*)初始值  (*)最终如何得到
涨工资的人数: countEmp number := 0;
涨后的工资总额:salTotal number;
(1)select sum(sal) into salTotal from emp;
(2)涨后=涨前 + sal *0.1

练习: 人数:8    总额:50205.325
*/
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
         -- 1. 总额 >5w
         exit when salTotal > 50000;
         --取一个员工
         fetch cemp into pempno,psal;
         --2. notfound
         exit when cemp%notfound;

         --涨工资
         update emp set sal=sal*1.1 where empno=pempno;
         --人数+1
         countEmp := countEmp +1;
         --涨后=涨前 + sal *0.1
         salTotal := salTotal + psal * 0.1;

    end loop;
    close cemp;

    commit;
    dbms_output.put_line(‘人数:‘||countEmp||‘    总额:‘||salTotal);
end;
/

实例3:

/*
1、SQL语句
部门:select deptno from dept; ---> 光标
部门中员工的薪水: select sal from emp where deptno=?? ---> 带参数的光标

2、变量:(*)初始值  (*)最终如何得到
每个段的人数
count1 number; count2 number; count3 number;
部门的工资总额
salTotal number := 0;
(1)select sum(sal) into salTotal  from emp where deptno=??
(2)累加
*/
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 := 0;
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;
/

原文地址:https://www.cnblogs.com/x54256/p/9010615.html

时间: 2024-11-05 17:34:12

Oracle——PL/SQL的相关文章

ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)

原文:ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) ORACLE PL/SQL编程之六: 把过程与函数说透(穷追猛打,把根儿都拔起!)   继上篇:ORACLE PL/SQL编程之八:把触发器说透 得到了大家的强力支持,感谢.接下来再下猛药,介绍下一篇,大家一定要支持与推荐呀~!我也才有动力写后面的.   本篇主要内容如下: 6.1 引言 6.2 创建函数 6.3 存储过程 6.3.1 创建过程 6.3.2 调用存储过程 6.3.3 AUTHID 6.3.4 

[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)

原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日之功) 继上四篇:ORACLE PL/SQL编程之八:把触发器说透                ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)                [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]

[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼、百战不殆)

原文:[推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼.百战不殆) [推荐]ORACLE PL/SQL编程之五: 异常错误处理(知已知彼.百战不殆) 继上三篇:ORACLE PL/SQL编程之八:把触发器说透 ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) 得到了大家的强力支持与建议,万分感谢.接下来介绍下一篇:oracle pl/sql异常处理部分,还望大家一定

【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航

原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人品牌. 本是成书的,但后来做其他事了,就无偿的贡献出来,被读者夸其目前为止最“实在.经典”的写ORACLE PL/SQL编程的文章-! 觉得对你有帮助,请留言与猛点推荐,谢谢. [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) 本篇主要内容如下:第一章 PL/S

[推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到)

原文:[推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]ORACLE PL/SQL编程之四: 把游标说透(不怕做不到,只怕想不到) 继上两篇:ORACLE PL/SQL编程之八:把触发器说透 ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) 得到了大家的强力支持,感谢.接下来再下猛药,介绍下一篇,大家一定要支持与推荐呀~!我也才有动力写后面的. 本篇主要内容如下: 4.1 游标概念 4.1.1 处理显式游标 4.1.2 处理

[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)

原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ——通过知识共享树立个人品牌. 继上五篇: [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [推荐]ORACLE PL/SQL编程之四:把游标说透(不怕做不到,只怕想不到) [推荐]ORACLE PL/SQL编程之五:异常错误处理(知已知彼.百战不

[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)

原文:[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) [推荐]ORACLE PL/SQL编程详解之一: PL/SQL 程序设计简介(千里之行,始于足下) ——通过知识共享树立个人品牌. 继上六篇: [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程之四:把游标说透(

[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天才在于积累!) ——通过知识共享树立个人品牌.   继上七篇:            [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)            [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之

ORACLE PL/SQL编程之八(一): 把触发器说透

本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8.2.2 创建DML触发器 8.2.3 创建替代(INSTEAD OF)触发器 8.2.3 创建系统事件触发器 8.2.4 系统触发器事件属性 8.2.5 使用触发器谓词 8.2.6 重新编译触发器 8.3 删除和使能触发器 8.4 触发器和数据字典 8.5   数据库触发器的应用举例 触发器是许多关系数据库系统都提供的一项技术.在O

ORACLE PL/SQL编程之八(二): 把触发器说透

例2:创建DML语句行级触发器.当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据.由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器. BEGIN  DBMS_OUTPUT.PUT_LINE('插入前');  Disp_dept_summary();  DBMS_UTILITY.EXEC_DDL_STATEM