===============笔记============
----------------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)
==============================