0
点赞
收藏
分享

微信扫一扫

plSql学习日志

楠蛮鬼影 2022-02-20 阅读 53
学习sqldba

文章目录

基础语法

plsql的HelloWorld

set serveroutput on
--打印Hello World
declare
    --说明部分(变量,光标或者例外说明)
begin
    --程序体(DML语句)
    dbms_output.put_line('Hello World');
end;

基本变量类型的使用

-- 使用基本变量类型
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(sysdate);
    --计算明天的日期
    DBMS_OUTPUT.PUT_LINE(pdate + 1);
end;

引用型变量和记录型变量

  • 引用型变量
    引用表中一列的类型作为我定义的变量类型
-- 引用型变量
set serveroutput on
declare
    --定义引用变量:查询打印7839的姓名和薪水
    --pename varchar2(20)
    --psal number;
    pename emp.ename%type;
    psal emp.sal%type;
begin
    --得到7839的姓名和薪水
    select ename,sal into pename,psal from emp where empno = 7839;
    --打印姓名和薪水
    dbms_output.put_line(pename||'的薪水是'||psal);
end;
  • 记录型变量
    存储一行的数据类型的数组
set serveroutput on
 --定义记录变量:查询打印7839的姓名和薪水
 set serveroutput on
 declare 
    --定义记录型变量:注意代表一行
    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;

If语句的使用

/*
判断用户从键盘输入的数字
1.如何使用if语句
2.接收一个键盘输入(字符串)
*/
set serveroutput on
--接收一个键盘输入
--num:地址值,含义是:该地址上保存了输入的值
accept num prompt '请输入一个数字';
declare
    --定义变量保存从键盘上输入的数字
    pnum number := #
begin
    --执行if语句进行条件判断
 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;

循环语句使用

  • while
--使用while循环打印数字1—10
set serveroutput on
declare
    --定义循环变量
    pnum number := 1;
begin
    while pnum <= 10 loop
        --循环体
        dbms_output.put_line(pnum);
        --使该变量+1
        pnum := pnum + 1;
    end loop;
end;
  • loop
--使用loop循环打印数字1—10
set serveroutput on
declare
    --定义循环变量
    pnum number := 1;
begin
   loop
        --退出条件:循环变量大于10
        exit when pnum > 10;
        --打印该变量的值
        dbms_output.put_line(pnum);
        --循环变量+1
        pnum := pnum+1;
   end loop;
end;

光标

  • 光标就是一个结果集(result set)
  • 例子1
--光标的使用例子:查询打印所有员工的薪水
set serveroutput on
/**
    %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 cemp%notfound;
        dbms_output.put_line(pename||'的薪水是'||psal);
    end loop;
    
    --关闭光标
    close cemp;
end;   
  • 例子2
--光标的使用例子:给员工涨工资,总裁1000,经理800,其他400
set serveroutput on
/**
    %found %notfound
*/
declare
    --定义一个光标代表给哪些员工涨工资
    cursor cemp is select empno,empjob from emp;
    --为光标定义对应的变量
    pempno emp.empno%type;
    pjob emp.empjob%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 = 'manger' 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;
    --对于oracle,默认的事务隔离级别是read committed
    commit;
    dbms_output.put_line('涨工资完成');
end;
  • 例子3:带参数的光标定义
--查询某个部门中员工的姓名
set serveroutput on
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;
end;

光标属性

/**
光标的属性
    %found %notfound
    %isopen:判断光标是否打开
    %rowcount:影响行数
*/
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;
        --打印rowcount的值
        dbms_output.put_line('rowcount:' || cemp%rowcount);
    end loop;
    
    close cemp;
end;

光标数限制

默认情况下oracle只允许在同一个回话中,打开300个光标。

  • 在管理员用户下查询当前允许打开多少个光标

SQL>show parameter cursor

NAMETYPEVALUE
cursor_bind_capture_destinationstringmemory+disk
cursor_invalidationstringIMMEDIATE
cursor_sharingstringEXACT
cursor_space_for_timebooleanFALSE
open_cursorsinteger300
session_cached_cursorsinteger50
  • 修改光标数的限制

SQL>alert system set open_cursors = 400 scope = both;

例外(异常)

  • 例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性。

  • 系统例外

--系统例外:no_data_found
set serveroutput 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;
--系统例外:too_many_rows
set serveroutput on
declare 
    pename emp.ename%type;
begin
    --查询员工是1234的员工姓名
    select ename into pename from emp where deptno = 20;
exception
    when too_many_rows then dbms_output.put_line('select into 匹配多行');
    when others then dbms_output.put_line('其他例外');
end;
--系统例外:zero_divide
set serveroutput on
declare 
    pnum number;
begin
    pnum := 1/0;
exception
    when zero_divide then dbms_output.put_line('0不能作为除数');
                           dbms_output.put_line('erro x/0');
    when others then dbms_output.put_line('其他例外');
end;
--系统例外:value_error
set serveroutput on
declare 
    pnum number;
begin
    pnum := 'abc';
exception
    when value_error then dbms_output.put_line('算术或者转换异常');
    when others then dbms_output.put_line('其他例外');
end;
  • 自定义例外
--系统例外:value_error
set serveroutput on
declare 
    --定义光标,代表50号部门的员工姓名
    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;
    dbms_output.put_line('抛出例外了,这里不执行');
    
    --oracle自动启动pmon(process monitor)
    --关闭光标
    close cempp;
exception
    when value_error then dbms_output.put_line('算术或者转换异常');
    when others then dbms_output.put_line('其他例外');
end;

案例

/*
需求统计2021年—2022年每年入职的员工人数
SQL语句
select to_char(hiredate,'yyyy') from emp;
->关标->循环->退出条件:notfound
变量:1.初始值 2.如何得到
每年入职的员工人数:
count21 number := 0;
count22 number := 0;
*/
set serverout on;
declare
   cursor cemp is select to_char(hiredate,'yyyy') from emp;
   phiredate varchar2(4);
   count21 number := 0;
   count22 number := 0;
begin
    open cemp;
    loop
        fetch cemp into phiredate;
        exit when cemp%notfound;
        if phiredate = '2022' then count22 := count22+1;
            elsif phiredate = '2021' then count21 := count21+1;
        end if;
    end loop;
    dbms_output.put_line('2022年入职的人数有:'||count22);
    dbms_output.put_line('2021年入职的人数有:'||count21);
    close cemp;
end;
/*
需求:为员工涨工资。从最低工资涨起每人涨10%,但所有人的工资总额不能超过5w,
请计算涨工资的人数和涨工资后的工资总额,并输出涨工资的人数和工资总额。
*/
set serveroutput on
declare
cursor cemp is select empno,sal from emp order by sal asc;
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;
        --涨后的工资总额=涨前的工资总额 + sal*0.1
        salTotal := salTotal + psal*0.1;
        if salTotal >= 50000 then
            --把salTotal还原
            salTotal := salTotal - psal*0.1;
        elsif salTotal < 50000 then
            --涨工资
            update emp set sal = sal*1.1 where empno = pempno;
            --人数 + 1
            countEmp := countEmp + 1;
        end if;
   end loop;
   close cemp;
   commit;
   dbms_output.put_line('涨工资人数:'||countEmp||' 涨后的工资总额:'||salTotal);
end;
/*
*实现按部门分段(6000以上、(6000、3000)、3000以下)统计各个工资的职工人数、以及
*各部门的工资总额(工资总额中不包括奖金)
*创建表msg存储统计数据
* create table msg(deptno number,count1 number,count2 number,count3 number,saltotal number)
*/
set serveroutput on
truncate table msg;
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;

创建表存储统计结果

create table msg1(
    coursename varchar2(20),
    dname varchar2(20),
    count1 number,
    count2 number,
    count3 number,
    avggrade number
);
set serveroutput on
declare 
    --系的光标
    cursor cdept is select dno,dname from dep;
    pdno dep.dno%type;
    pdname dep.dname%type;
    
    --成绩光标
    cursor cgrade(coursename varchar2,depno number)
        is select grade from sc where cno=(select cno from course where cname=coursename)
                                    and sno in (select sno from student where dno=depno);
    pgrade sc.grade%type; 
    --每个分数段的人数
    count1 number; count2 number; count3 number;
    --每个系选修了"大学物理" 学生的平均成绩
    avggrade number;
    
    --课程名称
    pcourseName varchar2(20):='大学物理';
    
begin
    --打开系的光标
    open cdept;
    loop
        --取一个系的信息
        fetch cdept into pdno,pdname;
        exit when cdept%notfound;
        --初始化工作
        count1:=0;count2:=0;count3:=0;
        --系的平均成绩
        select avg(grade) into avggrade from sc where cno=(select cno from course where cname=pcourseName) 
            and sno in (select sno from student where dno=pdno);
        --取系中,选修了大学物理的学生成绩
        open cgrade(pcourseName,pdno);
        loop
            --取出一个学生的成绩
            fetch cgrade into pgrade;
            exit when cgrade%notfound;
            --判断成绩的范围
            if pgrade<60 then count1:=count1+1;
                elsif pgrade>=60 and pgrade<85 then count2:=count2+1;
                else count3:=count3+1;
            end if;
        end loop;
        close cgrade;
        --保存当前的结构
        insert into msg1 values(pcourseName,pdname,count1,count2,count3,avggrade);
    end loop;
    --关闭系光标
    close cdept;
    commit;
    dbms_output.put_line('统计完成');
end;
举报

相关推荐

0 条评论