day74_oracle04_笔记

===============笔记============

----------------Oracle第四天-------------
概述:
PL/SQL:对sql语言的过程化扩展语言
procedure
  
内容大纲:
1、plsql基本语法  **【copy】
2、存储过程和存储函数 ***
3、jdbc调用存储过程和存储函数  *****没有笔记看代码(或讲义)
4、触发器 ****
5.拓展:数据误删掉emp表。oracle恢复方法:###(仅限oracle)

  
一、pl/sql基本语法**

==============总体格式:
[declare]
  ---声明部分:【大纲】
  --声明   变量(普通变量、引用型变量、记录型变量) 常量  异常  游标
begin
 
 [exception]
    捕获异常  

end;
===============
--1.1变量(普通变量、引用型变量、记录型变量)
--普通变量demo1:
declare
my_name varchar2(20):='tom'; --【:=就是赋值】
begin
  dbms_output.put_line(my_name);--【output页面输出结果】
end;
--普通变量demo2:
declare
my_name varchar2(20):='tom'; --java   private String v_name='TOM';
                             -- 【:=相当于Java中的=,  =相当于Java中的==】
my_num number(20):=100; 
my_date date:=sysdate; 
begin
  dbms_output.put_line(my_name||'---'||my_num||'---'||my_date);--【数据类型+连接符练习】
end;
--普通变量demo3:
declare
my_name varchar2(20):='tom'; 
my_num number(20):=100; 
my_date date:=sysdate;  
my_gender constant number(1):=1; 
begin
  my_name:='tom2';
  --my_gender:='0';--运行报错,修改无效
  dbms_output.put_line(my_name||'---'||my_num||'---'||my_date||'---'||my_gender);--【常量练习】
end;
--引用变量demo###:
declare 
 v_name varchar2(30):='TOM'; 
 v_sal emp.sal%type:=1000;--引用型【引用单个列的类型:定义当前变量 ###】
 v_row emp%rowtype;       --记录型【引用一行记录:对象型 ###】
begin
  --【######引用完毕,执行时封装数据到(into)声明的变量里】
  select ename,sal into v_name, v_sal from emp where empno=7369;--###-多个变量共用一个into
  select * into v_row from emp where empno=7369;
  dbms_output.put_line(v_name||'--'||v_sal||'---');--会自动换行
  dbms_output.put_line(v_row.ename||'--'||v_row.sal||'——'||v_row.job);
end;
----变量总结demo:
declare 
 --java   private String v_name='TOM';
 v_name varchar2(30):='TOM';   -- 【:=相当于Java中的=,  =相当于Java中的==】
 v_age number(9):=1;
 v_gender constant number(1):=1;  --常量 【constant修饰的变量】
 v_sal emp.sal%type:=1000;   --引用型
 v_row emp%rowtype;          --记录型
begin
  v_name:='JERRY'; 
  --v_gender:='0';
  select ename ,sal into v_name , v_sal from emp where empno=7369;
  select * into v_row from emp where empno=7369;
  --dbms_output.put_line(v_name||'--'||v_sal||'——'||v_gender);
  dbms_output.put_line(v_row.ename||'--'||v_row.sal||'——'||v_row.job);
end;
--1.2 流程语句
---if分支
语法一:
if  条件  then
  逻辑处理
end if;---基础语法。if then endif 三个关键字。

语法二:
if 条件 then
  逻辑处理
 else --###-注意不是else if:去空格和e:elsif
 逻辑处理
end if;

语法三:
if 条件 then
  逻辑处理
elsif 条件
  逻辑处理
 .......   
 else
 逻辑处理
end if;    
   
--练习:判断一个年龄数据,小于18 输出“未成年人”,18---60 “成年人” ,大于60输出“老年人”
declare
 v_age number(9):=&nums;---###【&合法任意字符,表示变量地址】 手动输入数字提示框。
begin
 if  v_age<18 then
   dbms_output.put_line('未成年人');
 elsif v_age>=18 and v_age<=60 then
    dbms_output.put_line('成年人');
 else
   dbms_output.put_line('老年人');
 end if;  
end;

--循环
--语法一:无条件循环,有条件退出
loop
  
end loop;---类比:if   end if;结构

--输出1到100个数
declare
 v_num number(9):=1;
begin
  loop
   --if v_num>100 then
   --  exit;
   --end if;    
   exit when v_num>100;--if的简化写法
   dbms_output.put_line(v_num);
   v_num:=v_num+1;
  end loop;---类比:if   end if;结构
end;

--语法二:有条件循环
while 条件
  loop
    
  end loop;
--输出1到100个数
declare
 v_num number(9):=1;
begin
  while v_num<=100
  loop
     dbms_output.put_line(v_num);
     v_num:=v_num+1;
  end loop; 
end;

--语法三:for循环
for 变量名 in 起始值..终止值
  loop
    
  end loop;
--输出1到100个数    ---变量声明可省略 
begin
  for v_num in 1..100
   loop
     dbms_output.put_line(v_num);
   end loop;  
end;
  

--1.3 异常   exception
异常的作用:为了提高语言的容错性和健壮性
--预定义 异常:oracle预定义异常文档。

declare
 v_num number(5);
 
begin
  --v_num:=10/0;  
  v_num:=1000000;  
 exception
   --VALUE_ERROR --值错误异常
   --ZERO_DIVIDE --被0除异常
   when others then --###-others:表示 所有的异常
   v_num:=0;  
  dbms_output.put_line(v_num);   
end;

--自定义 异常
-- 输一个年龄数据,大于150就抛异常
declare
 v_age number(10):=&nums;
 exc_age exception;---声明异常类型的变量exc_age。
begin
  if v_age>150 then
    raise exc_age ; ---声明异常类型的变量exc_age。
  end if;
  
  exception
    when exc_age then
      ---参数:p1 错误代码    p2 错误信息
     raise_application_error(-20001,'捕获了异常');----了解一下。
     -- v_age:=150;
     --dbms_output.put_line('捕获了异常,年龄重置成了150');
end;

--1.4 游标  [光标]   cursor
  --游标的声明语法:【cursor 游标名称 is sql查询语句】---is
  --使用游标的语法:
  open   游标名称
   loop
     exit when 游标名称%notfound;
     fetch 游标名称 into 记录型变量;
      逻辑处理
     
   end loop
  close 游标名称;
---实例1: 
declare
 cursor cursor_emp is select * from emp;--声明游标
 v_row emp%rowtype;---###记录型变量:【使用emp表类型的一行数据】
begin
   open   cursor_emp;--打开
   loop
     fetch cursor_emp into v_row;--【fetch从游标 获取数据】
     exit when cursor_emp%notfound;
     dbms_output.put_line(v_row.ename||'---'||v_row.job);
   end loop;
  close cursor_emp;--关闭
end;

---实例2: 
--带参数的游标
declare                    --带参数的游标:参数类型number 不能加(长度),参数个数任意
 cursor cursor_emp(v_no number,v_no1 number) is select * from emp where deptno=v_no or deptno=v_no1;
 v_row emp%rowtype;
begin
   open   cursor_emp(10,20);
   loop
     fetch cursor_emp into v_row;
     exit when cursor_emp%notfound;
     dbms_output.put_line(v_row.deptno||'---'||v_row.ename||'---'||v_row.job);
   end loop;
  close cursor_emp;
end;

---改动:结果order by deptno
declare                    --带参数的游标:参数类型number 不能加(长度),参数个数任意
 cursor cursor_emp(v_no number,v_no1 number) is 
        select * from emp where deptno in (v_no ,v_no1) order by deptno;
 v_row emp%rowtype;
begin
   open   cursor_emp(10,20);
   loop
     fetch cursor_emp into v_row;
     exit when cursor_emp%notfound;
     dbms_output.put_line(v_row.deptno||'---'||v_row.ename||'---'||v_row.job);
   end loop;
  close cursor_emp;
end;

-----【以上内容大概了解。下面的存储过程 是核心内容    ######(面试只会考察到存储过程)】------
二、存储过程:***** 【###### 语法比较难记,用的少记住也会忘.看懂大意不强记。】
--2.1存储过程
【是一段被命名化的plsql】,【预编译到数据库中】

--######--语法:
 create or replace procedure 存储过程名称(参数1 [in]/out 数据类型,  参数2 [in]/out 数据类型,...)
 is|as  --【替代了declare的作用】,如果没有变量声明时不能省掉
 
 begin
    
 end; 

--案例1:打印指定员工的年薪
--定义:###===
 create or replace procedure pro_yearsal(v_no number)--传参数:or replace 可以更新存储过程,便于测试
 is
  v_yearsal number(10,2);---变量
 begin
   select sal*12+nvl(comm,0)  into v_yearsal from emp where empno=v_no; ---过程体(类似方法体)定义:使用参数v_no
   dbms_output.put_line('年薪是:'||v_yearsal); --返回结果封装到v_yearsal。打印
 end; 

--使用:###===
select * from emp;
方式1:
call pro_yearsal(7788);---call关键字 方法调用形式。---方式一,参数只能是写死的。不如方式2灵活
方式2:
begin
  pro_yearsal(7788);---begin end---存储过程调用 方式二:可以通过传递变量实现动态传参
end;

--案例2:使用out参数接收指定员工的年薪
--定义;
create or replace procedure pro_yearsal(v_no number,v_yearsal out number)----v_yearsal out number
is
begin
   select sal*12+nvl(comm,0)  into v_yearsal from emp where empno=v_no; 
end; 
--调用:带out类型参数的存储过程
declare
v_sal number(10,2);--声明变量 接收返回值
begin
  pro_yearsal(7788,v_sal);--调用---存储过程调用 方式二:可以通过传递变量实现动态传参(输出参数)
  dbms_output.put_line(v_sal);
end; 

--2.2【存储函数】---了解(重点:存储过程)
--语法:
create or replace function 存储函数的名称(参数   数据类型...)
return 数据类型
is|as
begin
  return 具体的值;  
end;
--案例1:返回指定员工的年薪
--定义:存储函数 function
create or replace function func_yearsal(v_no number)
return number
is
 v_yearsal number(10,2);
begin
   select sal*12+nvl(comm,0)  into v_yearsal from emp where empno=v_no; 
   return v_yearsal;  
end;
--使用方式1:存储函数
declare
 v_sal number(10,2);
begin
 v_sal:= func_yearsal(7788);
 dbms_output.put_line(v_sal);
end;
--使用方式2:简化版
begin
 dbms_output.put_line(func_yearsal(7788));
end;

---###---总结 存储函数和存储过程的区别
1、语法不同
2、使用场景不同
   存储函数一般多被存储过程调用---
   存储过程多用于多个项目之间的数据访问---访问其他项目给你提供的存储过程。不会告诉你真实数据
3、sql中可以直接使用存储函数,但是不能直接使用存储过程。
   --sql中可以直接使用存储函数:
  select ename,func_yearsal(empno) from emp; 

select * from emp;


三、jdbc调用存储过程和存储函数  *****看代码:没有笔记。
--2.3 out参数类型是 游标的存储过程。
----【这里是:jdbc调用存储过程的内容。
------所以不用直接在这里使用这个存储过程 】

---案例场景:游标中放的是指定部门的所有员工
---需求:通过部门编号 获取该部门的所有员工信息。
---定义:【老师】
create or replace procedure proc_cursor (v_no number,cursor_emp out sys_refcursor)
--### 参数类型必须是这种类型的游标。知道这麽用就行了。【系统引用类型的游标】
is
begin
  open cursor_emp for select * from emp where deptno=v_no;
end;

---如何使用(调用)?---代码 jdbc访问。。。。看代码


四、触发器 ****
----------触发器   trigger
---###【当表中的数据发生改变时,定义的某些操作】
delete  insert  update
---######--语法模板:
create  or replace trigger 触发器名称 ---没有参数
before|after  ---改变前,改变后
delete | insert | update[of  列名]
on 表名
[for each row]

[declare]

begin
  
end;
---######--语法模板end

---案例1:
create  or replace trigger tri_emp ---也没有参数
after 
insert ---插入后执行触发器
on emp
--[for each row]
declare
begin
  dbms_output.put_line('新入职了一名员工');
end;

insert into emp(empno,deptno) values(1,10);

---案例2:
--假如'2017-10-20'系统维护,不能修改emp中的数据
----定义触发器:
create  or replace trigger tri_emp
before
delete or insert or update   ---增删改(emp表) 前执行触发器
--delete or insert or update or query   ---没有查询【数据不更改,不会触发触发器】
on emp
--[for each row]
declare
 v_dateStr varchar2(20);
begin
  --判断当天sysdate是否是'2017-10-20'
  select to_char(sysdate,'yyyy-mm-dd') into  v_dateStr from dual;
  if v_dateStr = '2017-10-20' then
    raise_application_error(-20002,'今天系统维护,不能修改emp中的数据');
  end if;
end;
---测试:
insert into emp(empno,deptno) values(2,10);
update emp set ename='AAAA' where empno=1;
delete from emp where empno=1;
select * from emp;

---案例3:
--### 实际应用案例:备份员工的工资数据
--步骤:
1、创建表
create table emp_sal_log(
eid number(10) primary key,
empno number(10),
sal0 number(10,2),--调整之前的工资
sal1 number(10,2),--调整之后的工资
logDate date ---调整时间
)
2、创建序列
create sequence seq_emp_sal_log 
3、创建触发器
------创建-----------
create  or replace trigger tri_emp_sal
after
update of sal ---###### 只对工资字段添加触发器
on emp
for each row  ---####### 出现了:【old或者:new 就使用for each row】否则报错:当前级别触发器不能用:new、:old
-- :new   :old  伪记录
declare
begin
  ---###### ---第一个字段:主键:序列生成;第二个字段:部门编号;修改前工资;修改后工资
  --- :new(即将插入的数据);:old(插入之后的数据)---在数据库是否有值。
  --- :new:修改后的数据(empno不会改变,所以仍然是:old也行?)
   insert into emp_sal_log values(seq_emp_sal_log.nextval,:new.empno, :old.sal,:new.sal,sysdate);
end;      

-------名词解释----------
----- :new(即将插入的数据);:old(插入之后的数据)---在数据库是否有值。
         :new  :old
update   非null 非null
delete   null   非null 
insert   非null  null
------使用测试触发器-----------
update emp set sal=10000 where empno=7369;

select * from emp_sal_log;
select * from emp;

update emp set deptno=10 where empno=7369;---修改部门,触发器不执行:emp_sal_log表不会添加记录

---案例4:触发器生成主键 小demo
1、创建表
create table t_demo(
tid number(10) primary key,
tname varchar2(10)
)
--问题产生:
insert into t_demo(tname) values('aaaa');---没加触发器:执行报错:主键不能为空

2、创建触发器
create  or replace trigger tri_demo
before
insert ---插入前,使用触发器 生成主键
on t_demo
for each row

declare

begin
  --### 插入之前对即将插入的对象赋id值
 select  seq_emp_sal_log.nextval into :new.tid from dual;---:new即将插入的数据:id
end;

3、再次测试
insert into t_demo(tname) values('aaaa');---加上触发器,执行成功

select * from t_demo;


五、拓展:数据误删emp表。oracle恢复方法:###(仅限oracle)

---数据误删两种情况:
--1.删掉了表(没有回收站 难解决)
drop table emp
----plsql Developer的recycle bin 文件夹下:有删掉的表。--相当于 回收站
---回收站里也删了,只能去找 oracle公司帮助

--2.清空了表数据
delete from emp where empno=1

 ---【恢复数据:只能解决:误删数据,表没有被删除】 
 ---例如要执行:
 delete from emp where empno=1
 --- 选中失误:---有时候是没有提示的
 执行了:delete from emp,数据被清空。
 ----恢复方法:【创建备份表(在某个具体时间,表数据存在)】
create table emp_bak
as
select * from emp as of TIMESTAMP to_timestamp('20171021 083435','yyyymmdd hh24miss');

---
  select * from emp_bak;--ok
  select * from emp


-----------------------小结:
1、plsql基本语法  **【copy】
2、存储过程和存储函数 ***
3、jdbc调用存储过程和存储函数  *****看代码:没有笔记。
4、触发器 ****

5.拓展:数据误删掉emp表。oracle恢复方法:###(仅限oracle)




==============================

你可能感兴趣的:(day74_oracle04_笔记)