复习内容:

PL/SQL的基本语法、记录类型、流程控制、游标的使用、

异常处理机制、存储函数/存储过程、触发器。

为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载

为了要有输出的结果,在写PL/SQL程序前都在先运行这一句:
set serveroutput on
结构:
declare
--声明变量、类型、游标
begin
--程序的执行部分(类似于java里的main()方法)
exception
--针对begin块中出现的异常,提供处理的机制
--when...then...
--when...then...
end;
举例1:
declare
   v_sal number(10); (注意每句话后面别忘记了分号,跟java中的一样)
begin
   select salary into v_sal from employees where employee_id = 100;
   dbms_output.put_line(v_sal);
end;
举例2:
declare
   v_sal number(10); (注意,这里声明的空间大小不能比原表中的小)
   v_email varchar2(20);
   v_hire_date date;
begin
   select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =

100;
   dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
end;
或者:
declare
   v_sal employees.salary%type;
   v_email employees.email%type;
   v_hire_date employees.hire_date%type;
begin
   select salary,email,hire_date into v_sal,v_email,v_hire_date from employees where employee_id =

100;
   dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);
end;

记录:
declare
   type emp_record is record(
      v_sal employees.salary%type,
      v_email employees.email%type,
      v_hire_date employees.hire_date%type
   );
   v_emp_record emp_record;
begin
   select salary,email,hire_date into v_emp_record from employees where employee_id = 100;
   dbms_output.put_line(v_emp_record.v_sal||','||v_emp_record.v_email||','||

   v_emp_record.v_hire_date);
end;

1、pl/sql基本的语法格式
2、记录类型 type ... is ...record(,,,);
3、流程控制:
3.1 条件判断(两种)
方式一: if ... then elseif then ... else ... end if;
方式二: case ... when ... then ...end;
3.2 循环结构(三种)
方式一:loop ... exit when ... end loop;
方式二:while ... loop ... end loop;
方式三:for i in ... loop ... end loop;
3.3 goto、exit
4.游标的使用(类似于java中的Iterator)
5.异常的处理

6.会写一个存储函数(有返回值)、存储过程(没有返回值)
7.会写一个触发器

复习记录类型:
declare
type emp_record is record(
   -- v_emp_id employees.employee_id%type,
   -- v_sal employees.salary%type
   v_emp_id number(10) := 120,
   v_sal number(10,2) :=12000
);
   v_emp_record emp_record;
begin
   -- select employee_id,salary into v_emp_record from employees where employee_id = 123;
   dbms_output.put_line('employee_id:'||v_emp_record.v_emp_id||' '||'salary:'||

   v_emp_record.v_sal);
end;
也可以升级一下,要是想对表的所有列都输出,则:(须注意输出的列名要跟表中的列名要一样)
declare
   v_emp_record employees%rowtype;
begin
   select * into v_emp_record from employees where employee_id = 123;
   dbms_output.put_line('employee_id:'||v_emp_record.employee_id||' '||'salary:'||

   v_emp_record.salary);
end;
使用记录来执行update操作:
declare
   v_emp_id number(10);
begin
   v_emp_id :=123;
   update employees
   set salary = salary + 100
   where employee_id = v_emp_id;
   dbms_output.put_line('执行成功!~~');
end;

流程控制:
查询150号员工的工资,若其工资大于或等于10000 则打印‘salary >= 10000’;
若在5000到10000之间,则打印‘5000 <= salary <10000’;否则打印‘salary < 5000’
declare
   v_sal employees.salary%type;
begin
   select salary into v_sal from employees where employee_id =150;
   if v_sal >= 10000 then dbms_output.put_line('salary >= 10000');
   elsif v_sal > 5000 then dbms_output.put_line('10000 > salary >= 5000');
   else dbms_output.put_line('salary < 5000');
   end if;
   dbms_output.put_line('salary:'||v_sal);
end;
利用case ... when ... then ... when ...then ... else ... end实现上题;
declare
   v_sal employees.salary%type;
   v_temp varchar2(20);
begin
   select salary into v_sal from employees where employee_id =150;
   v_temp :=
   case trunc(v_sal/5000) when 0 then 'salary < 5000'
                                    when 1 then '5000 <= salary < 10000'
                                    else 'salary >= 10000'
                                    end;
   dbms_output.put_line('salary:'||v_sal||' '||v_temp);
end;

查询出122号员工的job_id,若其值为 ‘IT_PROG’, 则打印‘GRADE:A’
                                                ‘AC_MGT’, 则打印‘GRADE:B’
                                                ‘AC_ACCOUNT’, 则打印‘GRADE:B’
                                                 否则打印‘GRADE:D’
declare
   v_job_id employees.job_id%type;
   v_temp varchar2(20);
begin
   select job_id into v_job_id from employees where employee_id =122;
   v_temp :=
   case v_job_id when 'IT_PROG' then 'A'
                       when 'AC_MGT' then 'B'
                       when 'AC_ACCOUNT' then 'C'
                       else 'D'
                       end;
   dbms_output.put_line('job_id:'||v_job_id||' '||v_temp);
end;
使用循环语句打印:1-100
declare
   v_i number(5) :=1;

begin
   loop
   dbms_output.put_line(v_i);
   exit when v_i >=100;
   v_i := v_i + 1;
   end loop;
end;
使用while实现:
declare
   v_i number(5) :=1;
begin
   while v_i <= 100 loop
     dbms_output.put_line(v_i);
     v_i := v_i + 1;
   end loop;
end;
使用for...in...loop...end loop;实现:
begin
   for c in 1..100 loop
     dbms_output.put_line(c);
   end loop;
end;

输出2-100之间的质数
declare
   v_i number(3):= 2;
   v_j number(3):= 2;
   v_flag number(1):= 1;
begin
   while v_i<=100 loop
     while v_j<=sqrt(v_i) loop
       if mod(v_i,v_j)=0 then v_flag:=0;
       end if;
       v_j:= v_j+1;
     end loop;
   if v_flag = 1 then dbms_output.put_line(v_i);
   end if;
   v_j :=2;
   v_i := v_i + 1;
   v_flag := 1;
   end loop;
end;
利用for循环实现输出2-100之间的质数:
declare
   v_flag number(1):= 1;
begin
   for v_i in 2..100 loop
     for v_j in 2..sqrt(v_i) loop
       if mod(v_i,v_j)=0 then v_flag:=0;
       end if;
     end loop;
     if v_flag=1 then dbms_output.put_line(v_i);
     end if;
     v_flag := 1;
   end loop;
end;
可以用goto改进一下:
declare
   v_flag number(1):= 1;
begin
   for v_i in 2..100 loop
       for v_j in 2..sqrt(v_i) loop
         if mod(v_i,v_j)=0 then v_flag:=0;
         goto label;
         end if;
      end loop;
     <<label>>
     if v_flag=1 then dbms_output.put_line(v_i);
     end if;
     v_flag := 1;
   end loop;
end;
打印1-100的自然数,当打印到50时,跳出循环 ,输出‘打印结束’:
begin
   for i in 1..100 loop
     if i=50 then goto label;
     end if;
   dbms_output.put_line(i);
   end loop;
<<label>>
   dbms_output.put_line('打印结束');
end;
或者:
begin
   for i in 1..100 loop
     if i=50 then dbms_output.put_line('打印结束');
     exit;
     end if;
   dbms_output.put_line(i);
   end loop;
end;

游标:
打印出80部门的所有的员工的工资:salary:XXX
declare
v_sal employees.salary%type;
--定义游标
cursor emp_sal_cursor is select salary from employees where department_id = 80;
begin
--打开游标
open emp_sal_cursor;
--提取游标
fetch emp_sal_cursor into v_sal;
while emp_sal_cursor%found loop
dbms_output.put_line('salary:'||v_sal);
fetch emp_sal_cursor into v_sal;
end loop;
--关闭游标
close emp_sal_cursor;
end;
可以进行优化如下:
declare
v_empid employees.employee_id%type;
v_lastName employees.last_name%type;
v_sal employees.salary%type;
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where

department_id = 80;
begin
open emp_sal_cursor;
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
while emp_sal_cursor%found loop
dbms_output.put_line('employee_id:'||v_empid||', '||'last_name:'||v_lastName||',

'||'salary:'||v_sal);
fetch emp_sal_cursor into v_empid,v_lastName,v_sal;
end loop;
close emp_sal_cursor;
end;
或者使用记录再优化一下:
declare
type emp_record is record(
v_empid employees.employee_id%type,
v_lastName employees.last_name%type,
v_sal employees.salary%type
);
v_emp_record emp_record;
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where

department_id = 80;
begin
open emp_sal_cursor;
fetch emp_sal_cursor into v_emp_record;
while emp_sal_cursor%found loop
dbms_output.put_line('employee_id:'||v_emp_record.v_empid||', '||'last_name:'||

v_emp_record.v_lastName||', '||'salary:'||v_emp_record.v_sal);
fetch emp_sal_cursor into v_emp_record;
end loop;
close emp_sal_cursor;
end;
可以使用for循环最优化:(注意:在for循环中它会自动的打开游标、提取游标,当提取完里面的数据后也会自动

的关闭游标)
declare
cursor emp_sal_cursor is select employee_id,last_name,salary from employees where

department_id = 80;
begin
for c in emp_sal_cursor loop
dbms_output.put_line('employee_id:'||c.employee_id||', '||'last_name:'||c.last_name||',

'||'salary:'||c.salary);
end loop;
end;

利用游标,调整公司中员工的工资:
工资范围            调整基数
0 - 5000              5%
5000 - 10000       3%
10000 - 15000     2%
15000 -               1%
实现:
declare
   cursor emp_cursor is select employee_id,salary from employees;
   v_empid employees.employee_id%type;
   v_sal employees.salary%type;
   v_temp number(4,2);
begin
   open emp_cursor;
   fetch emp_cursor into v_empid,v_sal;
   while emp_cursor%found loop
      if v_sal < 5000 then v_temp:=0.05;
      elsif v_sal < 10000 then v_temp:=0.03;
      elsif v_sal < 15000 then v_temp:=0.02;
      else v_temp:=0.01;
      end if;
   dbms_output.put_line(v_empid||','||v_sal);
   update employees
   set salary = salary * (1+v_temp)
   where employee_id = v_empid;
   fetch emp_cursor into v_empid,v_sal;
   end loop;
   close emp_cursor;
end;
用for循环实现
declare
   cursor emp_cursor is select employee_id,salary from employees;
   v_temp number(4,2);
begin
   for c in emp_cursor loop
      if c.salary <5000 then v_temp:=0.05;
      elsif c.salary <10000 then v_temp:=0.03;
      elsif c.salary <15000 then v_temp:=0.02;
      else v_temp:=0.01;
   end if;
   update employees
   set salary = salary * (1+v_temp)
   where employee_id = c.employee_id;
   end loop;
end;
隐式游标:更新员工salary(涨工资10),如果该员工没有找到,则打印“查无此人”信息:
begin
   update employees
   set salary = salary + 10
   where employee_id = 1001;
     if sql%notfound then dbms_output.put_line('查无此人');
     end if;
end;

异常:
预定义异常:(有24个预定义异常,可查表)
declare
   v_sal employees.salary%type;
begin
   select salary into v_sal from employees
   where employee_id > 100;
   dbms_output.put_line(v_sal);
exception
   when too_many_rows then dbms_output.put_line('输出的行数过多');
   when others then dbms_output.put_line('出现其它的异常了');
end;
非预定义异常:
declare
   e_deleteid_exception exception;
   pragma exception_init(e_deleteid_exception,-2292);
begin
   delete from employees
   where employee_id = 100;
exception
   when e_deleteid_exception then dbms_output.put_line('违反了完整性约束,故不能删除此用户');
   when others then dbms_output.put_line('出现其它的异常了');
end;
用户自定义异常:
declare
   e_sal_hight exception;
   v_sal employees.salary%type;
begin
   select salary into v_sal from employees where employee_id = 100;
   if v_sal > 10000 then raise e_sal_hight;
   end if;
exception
   when e_sal_hight then dbms_output.put_line('工资太高了');
   when others then dbms_output.put_line('出现其它的异常了');
end;
通过select...into...查询某人的工资,若没找到则打印出“未找到此数据”:
declare
   v_sal employees.salary%type;
begin
   select salary into v_sal from employees where employee_id = 1001;
exception
   when no_data_found then dbms_output.put_line('未找到此数据');
   when others then dbms_output.put_line('出现其它的异常了');
end;
更新指定员工工资,如工资小于300,则加100,对NO_DATA_FOUND异常,TOO_MANY_ROWS进行处理。
declare
   v_sal employees.salary%type;
begin
   select salary into v_sal from employees where employee_id = 1001;
   if v_sal < 300 then update employees set salary = salary + 100 where employee_id =101;
   end if;
exception
   when no_data_found then dbms_output.put_line('未找到此数据');
   when too_many_rows then dbms_output.put_line('输出的行数太多了');
   when others then dbms_output.put_line('出现其它的异常了');
end;
自定义异常:
更新指定员工工资,增加100;若指定员工不在,则抛出异常:NO_RESULT;
declare
   no_result exception;
begin
   update employees set salary = salary + 100 where employee_id = 1001;
   if sql%notfound then raise no_result;
   end if;
exception
   when no_result then dbms_output.put_line('查无此数据,更新失败');
   when others then dbms_output.put_line('出现其它异常');
end;

存储过程:
写个简单的hello_world存储函数
create or replace function hello_world
return varchar2
is (相当于declare,可以在其后面定义变量、记录、游标)
begin
   return 'helloworld';
end;
存储函数的调用:
begin
   dbms_output.put_line(hello_world);
end;
或者:
select hello_world from dual;

带参数的存储函数:
create or replace function hello_world1(v_logo varchar2)
return varchar2
is
begin
   return 'helloworld'||v_logo;
end;
调用:
select hello_world1('shellway') from dual
或者:
begin
   dbms_output.put_line(hello_world1('shellway'));
end;

定义一个获取系统时间的函数:
create or replace function get_sysdate
return varchar2
is
begin
   return to_char(sysdate,'yyyy-MM-dd HH24:mi:ss');
end;

定义带参数的函数,两个数相加
create or replace function add_param(v_num1 number,v_num2 number)
return number
is
   v_num3 number(10);
begin
   v_num3 := v_num1 + v_num2;
   return v_num3;
end;
调用:
select add_param(2,5) from dual;
或者:
begin
   dbms_output.put_line(add_param(5,4));
end;

定义一个函数:获取给定部门的工资总和,要求:部门号定义为参数,工资总额为返回值:
create or replace function get_sal(dept_id number)
return number
is
   v_sumsal number(10) := 0;
   cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
   for c in salary_cursor loop
   v_sumsal := v_sumsal + c.salary;
   end loop;
   return v_sumsal;
end;
调用:
select get_sal(80) from dual;

定义一个函数:获取给定部门的工资总和 和 该部门的员工总数(定义为OUT类型的参数)。
要求:部门号定义为参数,工资总额定义为返回值。
create or replace function get_sal(dept_id number,total_count out number)
return number
is
  v_sumsal number(10) := 0;
  cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
   total_count := 0;
   for c in salary_cursor loop
       v_sumsal := v_sumsal + c.salary;
       total_count := total_count + 1;
   end loop;
   return v_sumsal;
end;
调用:
declare
   v_count number(4);
begin
   dbms_output.put_line(get_sal(80,v_count));
   dbms_output.put_line(v_count);
end;

定义一个存储过程:获取给定部门的工资总和(通过out参数),要求部门号和工资总额定义为参数。
(注意:存储过程和存储函数是不一样的,存储函数有返回值而存储过程没有,调用时候存储过程直接调用)
create or replace procedure get_sal1(dept_id number,sumsal out number)
is
  cursor salary_cursor is select salary from employees where department_id = dept_id;
begin
  sumsal := 0;
  for c in salary_cursor loop
      sumsal := sumsal + c.salary;
  end loop;
  dbms_output.put_line(sumsal);
end;
调用:
declare
   v_sal number(10):=0;
begin
  get_sal1(80,v_sal);
end;

对给定部门(作为输入参数)的员工进行加薪操作,若其到公司的时间在(?,95)期间,为其加薪5%

(95,98)                  3%

(98,?)                   1%
得到以下返回结果:为此次加薪公司每月额外付出多少成三(定义一个OUT型的输出参数)
create or replace procedure add_sal(dept_id number,temp out number)
is
   cursor sal_cursor is select employee_id,salary,hire_date
   from employees where department_id = dept_id;
   v_temp number(4,2):=0;
begin
   temp := 0;
   for c in sal_cursor loop
       if to_char(c.hire_date,'yyyy') < '1995' then v_temp:=0.05;
       elsif to_char(c.hire_date,'yyyy') < '1998' then v_temp:=0.03;
       else v_temp:=0.01;
       end if;

update employees
   set salary = salary * (1+v_temp)
   where employee_id = c.employee_id;

temp := temp + c.salary*v_temp;
   end loop;
   dbms_output.put_line(temp);
end;
调用:
declare
   v_i number(10):=0;
begin
   add_sal(80,v_i);
end;

触发器:
触发事件:在INSERT,UPDATE,DELETE情况下会触发TRIGGER
触发时间:该TRIGGER是在触发事件发生之前(BEFORE)还是之后(AFTER)
触发器本身:该TRIGGER被触发之后的目的和意图,正是触发器本身要做的事情,如PL/SQL块
触发频率:有语句级(STATEMENT)触发器和行级(ROW)触发器
写一个简单的触发器:
create or replace trigger update_emp_trigger
after
   update on employees
for each row (行级触发器,即每更新一条记录就会输出一次'helloworld',若没有这语句则是语句级触发器)
begin
   dbms_output.put_line('helloworld');
end;

使用:new,:old修饰符:
1、
create table emp1
as
select employee_id,salary,email from employees where department_id = 80;
2、
create or replace trigger update_emp_trigger2
after
   update on emp1
for each row
begin
   dbms_output.put_line('old salary:'||:old.salary||'new salary:'||:new.salary);
end;
3、
update emp1 set salary = salary + 100 ;

编写一个触发器,在对my_emp记录进行删除的时候,在my_emp_bak表中备份对应的记录
1、创建my_emp表:
create table my_emp
as
select employee_id,salary from employees ;
2、创建my_emp_bak表:
create table my_emp_bak
as
select employee_id,salary from employees where 1=2;
3、检查创建的表中的记录:
select * from my_emp
select * from my_emp_bak
4、创建一个触发器:
create or replace trigger delete_emp_trigger
before
   delete on my_emp
for each row
begin
   insert into my_emp_bak
   values(:old.employee_id,:old.salary);
end;
5、执行含有触发器时间的语句:
delete from my_emp
6、检查触发器执行后的结果:
select * from my_emp
select * from my_emp_bak

吾时而躬身自省,自省使知已之不足,知不足而奋起,未为晚也!

oracle从入门到精通复习笔记续集之PL/SQL(轻量版)的更多相关文章

  1. PL/SQL轻量版(一)——入门介绍

    一.概述 1.概念对比: SQL:结构化查询语言(Structured Query Language)简称SQL(发音:/ˈes kjuː ˈel/ "S-Q-L"),是一种特殊目 ...

  2. oracle从入门到精通复习笔记

    为方便大家跟着我的笔记练习,为此提供数据库表文件给大家下载:点我下载 描述一个表用 desc employees过滤重复的部门 select distinct department_id from e ...

  3. Oracle从入门到精通----学习笔记

    书名:<Oracle从入门到精通:视频实战版>秦靖.刘存勇等编著 第4章 SQL基础 1.SQL语言分类 数据定义语言 --- DDL,Data Definition Language 数 ...

  4. php入门到精通(复习笔记)

    第一章:php语言基础 1,标记风格: ①<?php echo “hello”;?> ②<script language="php">echo " ...

  5. 《Oracle 11g 入门到精通.明日科技.pdf》学习笔记

    本博文整理者:刘军 本博文出自于: <Oracle 11g 入门到精通>一书 声明:1:转载请标注出处.本文不得作为商业活动.本人不负法律责任.违法者自负一切法律责任. ————————— ...

  6. 学习Oracle数据库入门到精通教程资料合集

    任何大型信息系统,都需要有数据库管理系统作为支撑.其中,Oracle以其卓越的性能获得了广泛的应用.本合集汇总了学习Oracle数据库从入门到精通的30份教程资料. 资料名称 下载地址 超详细Orac ...

  7. Oracle从入门到精通 限定查询和排序查询的问题

    视频课程:李兴华 Oracle从入门到精通视频课程 学习者:阳光罗诺 视频来源:51CTO学院 知识点 SQL语句的执行顺序 限定符号的使用.   具体内容: 如果想要对所选择的数据进行控制,就可以使 ...

  8. 干货分享!Oracle 的入门到精通 ~

    Oracle Database,又名Oracle RDBMS,或简称Oracle.是甲骨文公司的一款关系数据库管理系统.它是在数据库领域一直处于领先地位的产品.可以说Oracle数据库系统是目前世界上 ...

  9. 查询oracle数据库,返回的数据是乱码。 PL/SQL正常。

    查询oracle数据库,返回的数据是乱码. PL/SQL正常. 解决方案如下:

随机推荐

  1. php 导出Excel 不用安装插件、开启配置

    function export_csv($filename, $data) { header("Content-type:text/csv"); header("Cont ...

  2. opcache的配置

    ; Enable Zend OPcache extension module zend_extension=opcache.so ; Determines if Zend OPCache is ena ...

  3. Problem 63

    Problem 63 https://projecteuler.net/problem=63 Powerful digit counts The 5-digit number, 16807=75, i ...

  4. 第五节:numpy之数组维度处理

  5. PAT 1093. Count PAT's

    The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the 4th, and ...

  6. HTML5本地存储——Web SQL Database与indexedDB

    虽然在HTML5 WebStorage介绍了html5本地存储的Local Storage和Session Storage,这两个是以键值对存储的解决方案,存储少量数据结构很有用,但是对于大量结构化数 ...

  7. 联赛前集训日记Day1

    考试 炸的凄惨 T1 显然要高精搞一下,然而我的$DFS$竟然比我的$O(n^{2})$递推快 T2 欧拉路径的题,很不可做的样子,就没敢费时间打 T3 $DFS$枚举可过,然而我太蠢 GG 刷题 改 ...

  8. 清北学堂模拟赛d2t1 一道图论神题(god)

    题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有点权. LYK想把这个图删干净,它的方法是这样的.每次选择一个点,将它删掉,但删这个点是需要代价的.假 ...

  9. CODEVS2144 砝码称重2 (哈希表)

    由于m很大,所以不能使用DP. 注意到n≤30,直接暴力2^n会TLE. 所以,将砝码平均分成两份,对一份进行一次暴力,用哈希表存下可能的结果. 对下一份再进行一次暴力,在哈希表中搜索剩余的砝码重量是 ...

  10. data guard 的redo 传输

    data guard 通过把redo从primary数据库传输到standby数据库并应用在standby数据库来实现自己的功能. redo 传输是有2种模式 1. 同步 sync 2. 异步 asy ...