> 文档中心 > plSql学习日志

plSql学习日志

文章目录

  • 基础语法
    • plsql的HelloWorld
    • 基本变量类型的使用
    • 引用型变量和记录型变量
    • If语句的使用
    • 循环语句使用
  • 光标
    • 光标属性
    • 光标数限制
  • 例外(异常)
  • 案例

基础语法

plsql的HelloWorld

set serveroutput on--打印Hello Worlddeclare    --说明部分(变量,光标或者例外说明)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 ondeclare    --定义引用变量:查询打印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—10set serveroutput ondeclare    --定义循环变量    pnum number := 1;begin    while pnum <= 10 loop --循环体 dbms_output.put_line(pnum); --使该变量+1 pnum := pnum + 1;    end loop;end;
  • loop
--使用loop循环打印数字1—10set serveroutput ondeclare    --定义循环变量    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,其他400set 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 ondeclare    --定义带参数的光标    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 ondeclare    --定义光标    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

NAME TYPE VALUE
cursor_bind_capture_destination string memory+disk
cursor_invalidation string IMMEDIATE
cursor_sharing string EXACT
cursor_space_for_time boolean FALSE
open_cursors integer 300
session_cached_cursors integer 50
  • 修改光标数的限制

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

scope的取值:both,memory(只更改当前实例,不更改配置文件),spfile(数据库需要重启)

例外(异常)

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

  • 系统例外

--系统例外:no_data_foundset serveroutput ondeclare     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_rowsset serveroutput ondeclare     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_divideset serveroutput ondeclare     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_errorset serveroutput ondeclare     pnum number;begin    pnum := 'abc';exception    when value_error then dbms_output.put_line('算术或者转换异常');    when others then dbms_output.put_line('其他例外');end;
  • 自定义例外
--系统例外:value_errorset serveroutput ondeclare     --定义光标,代表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 ondeclarecursor 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 ontruncate 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;

用plsql语言编写一个程序。按系(系名)分段同(成绩小于60分,60-80分,85分以上)
"大学物理"课程各分数段学生的人数,以及各系学生人数,及各系学生的平均成绩。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuTnYMe5-1645290725099)(img/1.png)]

创建表存储统计结果

create table msg1(    coursename varchar2(20),    dname varchar2(20),    count1 number,    count2 number,    count3 number,    avggrade number);

分析:
1、得到有哪些系
select dno,dname from dep;–>光标–>循环–>退出条件:notfound
2、得到系中,选修了"大学物理"课程学生的成绩
select grade from sc where cno=(select cno from where cname=??)
and sno in (select sno from student where dno=??)
带参数的光标 —> 循环 —> 退出条件:notfound
变量:1.初始值 2.如何得到
每个分数段人数
count number;count2 number; count3 number;
每个系选修了"大学物理"学生的平均成绩
avggrade number;
1、算术运算
select avg(grade) into avggrade from sc where cno = (select cno from course where cname=??)
and sno in (select sno from student where dno=??);

set serveroutput ondeclare     --系的光标    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;