0
点赞
收藏
分享

微信扫一扫

Oracle数据库工程师技术实战索引和PLSQL

phpworkerman 2022-10-22 阅读 87

索引INDEX​

索引的概念特性和作用​

概念:

简单的说,相当于一本书的目录。(数据库中的索引相当于字典的目录(索引)),它的作用就是提升查询效率。

特性:

  • 一种独立于表的模式(数据库)对象, 可以存储在与表不同的磁盘或表空间中
  • 索引被删除或损坏, 不会对表(数据)产生影响, 其影响的只是查询的速度。
  • 索引一旦建立, Oracle 管理系统会对其进行自动维护,而且由 Oracle 管理系统决定何时使用索引. 用户不用在查询语句中指定使用哪个索引。
  • 在删除一个表时, 所有基于该表的索引会自动被删除。
  • 如果建立索引的时候,没有指定表空间,那么默认索引会存储在哪个表空间.会存储在所属用户默认的表空间.作用:
  • 通过指针(地址)加速Oracle 服务器的查询速度
  • 提升服务器的i/o性能(减少了查询的次数);


索引的工作原理​


Oracle数据库工程师技术实战索引和PLSQL_赋值


操作索引​

索引的常见操作可以创建、删除。

创建索引 ​

索引有两种创建方式:

  • 自动创建:在定义 PRIMARY KEY 或 UNIQUE 约束后系统自动在相应的列上创建唯一性索引。
  • 手动创建: 用户可以在其它列上创建非唯一的索引,以加速查询。


唯一索引的数据不重复,一般用于主键或唯一约束上创建。

其他普通的列的数据,一般可以重复,那么就不要创建唯一索引,创建一个非唯一、普通索引。

注意:索引也是公有对象

1. 自动创建

【示例】主键自动创建索引

--在emp表的empno上增加主键PK_EMP

Oracle数据库工程师技术实战索引和PLSQL_sql_02

思考:

创建主键的同时自动创建索引的好处(数据库的机制):是为了提高查询速度,一般业务中通过主键查询的比较频繁。


  1. 手动创建

语法:

Oracle数据库工程师技术实战索引和PLSQL_赋值_03


提示:可以在一个列或多个列上同时创建索引。

提示:如果在多个列上创建索引,也称之为联合索引

【示例】手动创建索引


--在指定的表空间上创建索引

--使用工具:

Oracle数据库工程师技术实战索引和PLSQL_sql_04

--生成的sql:

-- Create/Recreate indexes

createindex idx_emp_ename on EMP (ename);


--如果在生产环境下,创建表空间的脚本最好不要指定表空间的具体参数,例如下图的深蓝色的地方去掉

Oracle数据库工程师技术实战索引和PLSQL_sql_05



删除索引​

语法:

Oracle数据库工程师技术实战索引和PLSQL_sql_06


【示例】删除上例建立的索引idx_emp_ename

Drop index idx_emp_ename;


执行计划Explain Plan​

如何来查看索引是否生效以及预估索引性能效果呢?

采用执行计划。这里我们使用工具的执行计划功能。


打开执行计划窗口有两种方式:

  • 直接打开执行计划的空窗口,然后输入需要执行的SQL查询语句。
  • Oracle数据库工程师技术实战索引和PLSQL_赋值_07


  • 在SQL查询窗口中的语句上,按F5,可以自动打开执行计划窗口,并且会将选中的SQL语句自动填入执行计划窗口中自动执行。

Oracle数据库工程师技术实战索引和PLSQL_sql_08


下面我们演示一下如何查看索引的使用情况和效率

【准备数据】--补充知识:脚本的执行

Oracle数据库工程师技术实战索引和PLSQL_sql_09


Oracle数据库工程师技术实战索引和PLSQL_赋值_10


将准备好的脚本在数据库执行。执行脚本有两种方式:

  1. 使用command窗口的editor子窗口执行。将脚本直接粘贴到editor窗口,然后点击执行按钮或按F8:
  2. Oracle数据库工程师技术实战索引和PLSQL_数据_11


  3. 注意:
    命令行中执行的脚本在最后面要加上一个符号标识脚本终止,可以执行了。

  4. 在命令行使用@方式执行

在命令行下执行:@sql脚本路径,如:

@D:\教学\JavaWeb\16oracle\bigdatatest.sql

Oracle数据库工程师技术实战索引和PLSQL_赋值_12


第二种方法适合大量脚本的批量执行。推荐


@E:\教学资料\JavaWeb-IDEA版\02-oracle\资料\getsql.sql;

Oracle数据库工程师技术实战索引和PLSQL_sql_13




演示索引的效率查看​


--在testname字段上创建索引

Oracle数据库工程师技术实战索引和PLSQL_sql_14

--查询语句:


--创建索引前后的结果对比:

Oracle数据库工程师技术实战索引和PLSQL_sql_15



强制索引—了解​

在查询字段上增加索引后,查询操作时索引一定会生效么?

将上面的语句修改一下,执行后发现索引没有生效:


select * from bigdatatest where testname <> 'name775';

Oracle数据库工程师技术实战索引和PLSQL_赋值_16


效果:索引失效!



解决方案是:使用强制索引。

强制索引的语法:

/*+INDEX(表名,索引名字)*/


SELECT /*+index(bigdatatest,idx_bdt_testname)*/ * FROM bigdatatest WHERE testname <> 'name775';



【示例】

Oracle数据库工程师技术实战索引和PLSQL_数据_17

强制索引对于超大的数据量的表来说是有一定的作用的,虽然它是全索引扫描,但扫描索引比扫描表速度还是快。


强制索引的使用注意:

  1. 尽量少用强制索引,如何避免使用,条件上尽量不要用 <>, like%aa%
  2. 如果要用强制索引,在非常大的数据量的情况下使用。


索引的创建场景​

索引不是万能!

  • 以下情况可以创建索引:
  • 中数据值分布范围很广
  • 列经常在 WHERE 子句或连接条件中出现
  • 表经常被访问而且数据量很大 ,访问的数据大概占数据总量的2%到4%
  • 很小
  • 列不经常作为连接条件或出现在WHERE子句中
  • 查询的数据小于2%到4%
  • 表经常频繁更新(看需求,如果表经常不断的再更新,Oracle会频繁的重新改动索引,反而降低了数据库性能。但如系统日志历史表,就必须增加索引,效率超高)
  • 下列情况不要创建索引:


面试题:

1. 索引的作用是什么?

主要是提高查询效率,减少磁盘的读写,从而提高数据库性能。

2. 创建索引一定能提高查询速度么?

未必!得看你创建的索引的合理性。

3. 索引创建的越多越好么?

不是!索引也是需要占用存储空间的,过多的索引不但不会加速查询速度,反而还会降低效率。

友情提示:如果数据非常大的情况下,增加索引,一定要在业务低峰期操作,因为会花费一些时间。(排它锁)

4.如何创建索引?

create index idx_emp_ename on EMP (ename);

5.索引提了查询效率,你知道为什么提高查询效率?

因数据在底层根据创建过引的字段进行分组,查询减少扫描的次数

PLSQL编程​

概念和目的​

什么是PL/SQL?

  • PL/SQL(Procedure Language/SQL)
  • PLSQL是Oracle对sql语言的过程化扩展
  • 指在SQL命令语言中增加了过程处理语句(如分支、循环等),使SQL语言具有过程处理能力。(具有编程的能力)


为什么要学习plsql?

  1. 将sql逻辑写在db层,效率更高----数据库处理数据更专业,还不需要网络数据交换。
  2. 为存储过程、函数等打下基础,前提是学会plsql


Hello World​

通过程序在控制台打印一句话

一般我们调试或者练习plsql程序可以用test窗口(专门用来调试或练习的)

--建议在test窗口进行练习有提示

--过程化的语言,类似与basic

declare

begin

--打印一句话

--下面这句话相当于java:System.out.println("hello world");

--dbms_output:Oracle的内置包,相当于java类

--put_line:方法,相当于println

dbms_output.put_line('hello world');

end;


Oracle数据库工程师技术实战索引和PLSQL_数据_18

--点击运行或者F8




先分析一下:

--面向过程的语言

--declare声明部分:没有变量,则declare可以省略

你不需要变量声明,则不需要写任何东西

BEGIN--程序体的开始:编写语句逻辑

在控制台输出一句话:dbms_output相当于system.out类,内置程序包,put_line:相当于println()方法

dbms_output.put_line('Hello World');

--dbms_output.put('Hello World');


end;--程序体的结束


概念:程序包dbms_output相当于java中的类(system.out),它是oracle自带的,内置.

调用程序包dbms_output.put_line(‘Hello World!’)相当于java的方法


程序结构​

PL/SQL可为三个部分:声明部分、可执行部分、常处理部分

[declare]

声明部分(变量)

begin

DML语句、赋值、循环、条件等)

[exception]

异常处理部分(when 预定义异常错误 then

end;

/


简单的PL/SQL:

Begin

Null;

End;


注意:在SQLPLUS中PLSQL执行时,在最后加上一个 /

Oracle数据库工程师技术实战索引和PLSQL_赋值_19


变量​

语法说明​

声明部分可以定义变量,定义变量的语法

变量[CONSTANT]数据类型;

Oracle数据库工程师技术实战索引和PLSQL_数据_20


常见的几种变量类型的定义方法,分两大类:

  • 普通数据类型(char, varchar2, date, number, boolean, long):
  • Oracle数据库工程师技术实战索引和PLSQL_sql_21


  • 特殊变量类型(引用型变量、记录型变量):

Oracle数据库工程师技术实战索引和PLSQL_数据_22



普通变量赋值​

在ORACLE中有两种赋值方式:

1,直接赋值语句 :=

2, 使用select …into … 赋值:(语法;select 值 into 变量)


【示例】

打印几个变量的值,几个变量的值分别采用两种不同的赋值方法:

--打印两个变量的值,两个变量的值分别采用两种不同的赋值方法:

DECLARE--声明变量

--姓名

v_name VARCHAR(20) :='yanqi';--声明的时候直接赋值

--薪资

v_sal NUMBER;

--工作地点

v_local VARCHAR(200);

BEGIN--开始程序逻辑

--程序运行时赋值

--方法一:--直接赋值

v_sal :=9999;

--方法二:语句赋值

SELECT'上海'INTO v_local FROM dual;

--输出打印

dbms_output.put_line('姓名:'||v_name||',薪资:'||v_sal||',工作地点:'||v_local);

END;--程序结束



plsql中有两种不同的赋值方法:

一种是:直接用:=来赋值

另一种:select 值变量 from 表名。



引用变量:引用表字段的类型 (推荐使用引用类型)

%type 例: emp.ename%type;

使用emp表的字段ename的数据类型作为v_ename的数据类型.

【示例】

查询并打印7839号(老大)员工的姓名和薪水

--查询并打印7839号(老大)员工的姓名和薪水

DECLARE

--定义变量

--姓名

v_ename emp.ename%TYPE;--姓名使用的emp表中的ename的字段的数据类型

--薪水

v_sal emp.sal%TYPE;--你不需要关心具体什么数据类型了


BEGIN

--赋值

--注意:into前后字段名和变量名必须对应(不管是数据类型,还是个数,顺序)

--必须:查询的结果必须只有一个值,不能有多行记录

SELECT ename,sal INTO v_ename,v_sal FROM emp WHERE empno=7839;

--打印

dbms_output.put_line('7839号员工的姓名是:'||v_ename||',薪资'||v_sal);

END;


引用类型的好处:

  1. 使用普通变量定义方式,需要知道表中列的类型,而使用引用类型,需要考虑列的类型普通变量值过小报错:
  2. Oracle数据库工程师技术实战索引和PLSQL_数据_23


  3. 使用引用类型,当列中的数据类型发生改变,不需要修改变量的类型。而使用普通方式,当列的类型改变时,需要修改变量的类型

使用%TYPE是非常好的编程风格,因为它使得PL/SQL更加灵活,更加适应于对数据库定义的更新。


记录型变量​

记录型变量,代表一行,可以理解为数组里面元素是每一字段值。

%rowtype 引用一条(行)记录的类型 v_emp emp%rowtype;

含义:v_emp 变量代表emp表中的一行数据的类型,它可以存储emp表中的任意一行数据。

记录型变量分量的引用方式:

Oracle数据库工程师技术实战索引和PLSQL_赋值_24


【示例】

查询并打印7839号(老大)员工的姓名和薪水

--查询并打印7839号(老大)员工的姓名和薪水

DECLARE

--记录型变量

v_emp emp%ROWTYPE;--该变量可以存储emp表中的一行记录记录的是一行的数据类型


BEGIN

--赋值

--默认情况下,必须是全字段赋值

SELECT * INTO v_emp FROM emp WHERE empno=7839;

--打印

dbms_output.put_line('7839号员工的姓名是:'||v_emp.ename||',薪资'||v_emp.sal);

END;

场合:

如果有一个表,有100个字段,那么你程序如果要使用这100字段话,如果你使用引用型变量一个个声明,会特别麻烦,那么你可以考虑记录型变量


错误的使用:

  1. 记录型变量只能存储一个完整的行数据

Oracle数据库工程师技术实战索引和PLSQL_sql_25


2.From emp返回的行太多了,记录型变量也接收不了,因为只接受一行

Oracle数据库工程师技术实战索引和PLSQL_赋值_26



流程控制​

以执行就是对PL/SQL进行程序控制

程序控制

  1. 顺序结构
  2. 条件结构
  3. 循环结构


条件分支IF​

语法:

Oracle数据库工程师技术实战索引和PLSQL_数据_27


提示:语法和java作用差不多。

java三种if语法:

if(){

}


if(){

}else{
}


if(){

}else if(){
}else{
}

注意单词。


【示例】

判断emp表中记录是否超过20条,10-20之间,10以下打印一句

--判断emp表中记录是否超过20条,,10-20之间,10以下打印一句

DECLARE

--用来存储数量

v_count NUMBER;

BEGIN

--查询数量赋值

SELECTCOUNT(1) INTO v_count FROM emp ;

--判断

IF v_count>20THEN

dbms_output.put_line('记录数超过20条:'||v_count);

ELSIF v_count BETWEEN10AND20THEN

dbms_output.put_line('记录数在10到20条之间:'||v_count);

ELSE

dbms_output.put_line('记录数不足10条:'||v_count);

ENDIF;

END;


循环​

语法:

Oracle数据库工程师技术实战索引和PLSQL_sql_28


在ORACLE中有三种循环:

Loop 循环 EXIT WHEN...条件 end loop;

While()…loop 条件判断循环

For 变量 in起始..终止 Loop


这里我建议只记忆一种写法:

记住loop的写法


【示例】

打印数字1-10

--打印数字1-10

declare

--声明变量,初始值1

v_num number := 1;


begin

-- 循环

Loop

exitwhen v_num > 10;-- 退出条件

-- 不满足退出条件,继续输出

dbms_output.put_line(v_num);

-- v_num++

v_num := v_num+1;

endloop;


end;

Oracle数据库工程师技术实战索引和PLSQL_数据_29



游标(Cursor)​

什么是游标​

游标( Cursor[ˈkɜːsə(r)] ),也称之为光标

游标是映射在结果集中一行数据上的位置实体。

游标是从表中检索出结果集,并从中每次指向一条记录进行交互的机制。

游标从概念上讲基于数据库的表返回结果集,也可以理解为游标就是个结果集,但该结果集是带向前移动的指针的,每次只指向一行数据。

Oracle数据库工程师技术实战索引和PLSQL_sql_30


游标的主要作用:用于临时存储一个查询返回的多行数据(结果集),通过遍历游标,可以逐行访问处理该结果集的数据。


(显示)游标的使用方式:声明--->打开--->读取--->关闭


语法​

游标声明:

CURSOR 游标名 [ (参数名 数据类型[,参数名 数据类型]...)]

IS SELECT 语句;

【示例】

无参游标:

cursor c_emp is select ename from emp;

有参游标:

cursor c_emp(v_deptno emp.deptno%TYPE) is select ename from emp where deptno=v_deptno;

游标的打开:

Open 游标名(参数列表)

【示例】

open c_emp;-- 打开游标执行查询

游标的取值:

fetch 游标名 into 变量列表|记录型变量

【示例】

fetch c_emp into v_ename;--取一行游标的值到变量中,注意:v_ename必须与emp表中的ename列类型一致。(v_ename emp.ename%type;)

游标的关闭:

close 游标名

【示例】

close c_emp;--关闭游标释放资源

解释游标获取数据的基本原理:

游标刚open的时候,指针结果集的第一条记录之前。

游标与结果集的区别是什么?游标是有位置

fetch会向前游动,并获取游标的位置的内容。

Oracle数据库工程师技术实战索引和PLSQL_赋值_31


注意:游动过的就不能回来了,循环一次就到头。


游标的属性​

游标的属性

返回值类型

说明

%ROWCOUNT

整型

获得FETCH语句返回的数据行数

%FOUND

布尔型

最近的FETCH语句返回一行数据则为真,否则为假

%NOTFOUND

布尔型

与%FOUND属性返回值相反,代表游标结束

%ISOPEN

布尔型

游标已经打开时值为真,否则为假


创建和使用​

【示例】

使用游标查询emp表中所有员工的姓名和工资,并将其依次打印出来。


【引用型变量获取游标的值】:


--使用游标查询emp表中所有员工的姓名和工资,并将其依次打印出来。

DECLARE

--声明一个游标

CURSOR C_EMP IS

SELECT ENAME, SAL FROM EMP;

--引用型变量

V_ENAME EMP.ENAME%TYPE; --姓名

V_SAL EMP.SAL%TYPE; --工资


BEGIN

--打开游标,执行查询

OPEN C_EMP;

--使用游标,循环取值

LOOP

--获取游标的值放入变量的时候,必须要into前后要对应(数量和类型)

FETCH C_EMP INTO V_ENAME, V_SAL;

EXITWHEN C_EMP%NOTFOUND; --当取不到数据就退出

--输出打印

DBMS_OUTPUT.PUT_LINE('员工的姓名:' || V_ENAME || ',员工的工资' || V_SAL);

ENDLOOP;

CLOSE c_emp ;--关闭游标,释放资源

END;




【使用记录型变量存值】

--使用游标查询emp表中所有员工的姓名和工资,并将其依次打印出来。

DECLARE

--声明一个游标

CURSOR C_EMP ISSELECT * FROM EMP;

--记录型变量

v_emp emp%ROWTYPE;


BEGIN

--打开游标,执行查询

OPEN C_EMP;

--使用游标,循环取值

LOOP

--获取游标的值放入变量的时候,必须要into前后要对应(数量和类型)

FETCH C_EMP INTO v_emp;

EXITWHEN C_EMP%NOTFOUND;

--输出打印

DBMS_OUTPUT.PUT_LINE('员工的姓名:' || v_emp.ename || ',员工的工资' || v_emp.sal);

ENDLOOP;

CLOSE c_emp ;--关闭游标,释放资源

END;



带参数的游标​

【示例】

使用游标查询并打印某部门的员工的姓名和薪资,部门编号为运行时手动输入。


---查询10号部门的员工的姓名和薪资

declare

--定义游标--带参数的游标:需要定一个形式参数

CURSOR c_emp(v_deptno emp.deptno%TYPE) ISSELECT ename,sal FROM emp WHERE deptno=v_deptno ;


--声明变量使用引用类型

v_ename emp.ename%TYPE;

v_sal emp.sal%TYPE;


BEGIN

--用

--打开游标

OPEN c_emp(10);

--循环fetch

LOOP

--取出数据

FETCH c_emp INTO v_ename,v_sal;

--退出条件

EXITWHEN c_emp%NOTFOUND;

--打印--写任何的逻辑

dbms_output.put_line('姓名:'||v_ename||',薪资:'||v_sal);

ENDLOOP;

--关闭

CLOSE c_emp;

end;



--使用游标查询并打印某部门的员工的姓名和薪资,部门编号为运行时手动输入。

DECLARE

--声明一个带参数的游标

CURSOR C_EMP(v_deptno emp.deptno%TYPE) ISSELECT * FROM EMP WHERE deptno=v_deptno;

--记录型变量

v_emp emp%ROWTYPE;


BEGIN

--打开游标,执行查询

--打开游标的时候需要传入参数

OPEN C_EMP(20);

--使用游标,循环取值

LOOP

--获取游标的值放入变量的时候,必须要into前后要对应(数量和类型)

FETCH C_EMP INTO v_emp;

EXITWHEN C_EMP%NOTFOUND;

--输出打印

DBMS_OUTPUT.PUT_LINE('员工的姓名:' || v_emp.ename || ',员工的工资' || v_emp.sal);

ENDLOOP;


CLOSE c_emp ;--关闭游标,释放资源

END;


存储过程​

概念作用​

存储过程:就是一块PLSQL语句包装起来,起个名称

语法上:相当于plsql语句戴个帽子。

相对而言:单纯plsql可以认为是匿名程序。


提示:

  • plsql是存储过程的基础。
  • java是不能直接调用plsql的,但可以通过存储过程这些对象来调用。


语法​

Oracle数据库工程师技术实战索引和PLSQL_数据_32


As和is是通用的。


根据参数的类型,我们将其分为3类讲解:

  • 不带参数的
  • 带输入参数的
  • 带输入输出参数的。


无参存储​

创建存储​

最简单,就是包装了一个代码块

建议用这个窗口:

Oracle数据库工程师技术实战索引和PLSQL_数据_33


【示例】

create or replace procedure p_hello--没有参数的情况下,不要加()

IS

BEGIN --plsql程序

dbms_output.put_line('hello world');

end p_hello;


查询是否创建:

在工具procedures这里

Oracle数据库工程师技术实战索引和PLSQL_赋值_34



关于写存储的3个窗口的选择:

Oracle数据库工程师技术实战索引和PLSQL_sql_35



编译发布的时候使用command、测试使用test

调用方法​

如何调用执行,两种方法:

  • 一种是是用exec(execute)命令来调用—用来测试存储
  • 一种是用其他的程序(plsql)来调用


  • 命令调用的方式:
  • Oracle数据库工程师技术实战索引和PLSQL_数据_36


  • 程序调用

(通过代码, 可以调用多次)

BEGIN

p_hello;

p_hello;

p_hello;

p_hello;

p_hello;

p_hello;

END;

/

Oracle数据库工程师技术实战索引和PLSQL_赋值_37



注意

第一个问题:is和as是可以互用的,用哪个都没关系的
个问题:存储过程中没有declare关键字,declare用在语句块中


存储可以带参数可以不带参数?其实都有应用.

不带参数的存储一般用来处理内部数据的。不需要输入参数也不需要结果的,是可以使用。

带输入参数in​

【示例】

查询并打印某个员工(如7839号员工)的姓名和薪水--存储过程:要求,调用的时候传入员工编号,自动控制台打印。

--查询并打印7839号员工的姓名和薪水--存储过程:要求,调用的时候传入员工编号,自动控制台打印。

--i_empno输入参数的名字,IN代表是输入值的参数,

createorreplaceprocedure p_queryempsal(i_empno IN emp.empno%TYPE)

IS

--声明变量

v_ename emp.ename%TYPE;

v_sal emp.sal%TYPE;

BEGIN

--赋值

SELECT ename ,sal INTO v_ename,v_sal FROM emp WHERE empno= i_empno;

--打印

dbms_output.put_line('姓名:'||v_ename||',薪水:'||v_sal);

end p_queryempsal;


命令调用:

Oracle数据库工程师技术实战索引和PLSQL_赋值_38


程序调用:

BEGIN

p_queryempsal(7839);

END;


带输入in和输出参数out—主要是其他程序用的。​

【示例】

输入员工号查询某个员工(7839号员工)信息,要求,将薪水作为返回值输出,给调用的程序使用。

----输入员工号查询某个员工(7839号(老大)员工)信息,要求,将薪水作为返回值输出,给调用的程序使用。

CREATEORREPLACEPROCEDURE p_queryempsal_out( i_empno IN emp.empno%TYPE,o_sal OUT emp.sal%TYPE)

AS

BEGIN

--赋值:将薪水的值赋给输出的参数o_sal

SELECT sal INTO o_sal FROM emp WHERE empno=i_empno;


END;


调用(使用plsql程序调用):


DECLARE

--输入参数值

v_empno emp.empno%TYPE:=7839;

--声明一个变量来接收输出参数

v_sal emp.sal%TYPE;


BEGIN


p_queryempsal_out(v_empno,v_sal);--第二个参数是输出的参数,必须有变量来接收!!

--当上面的语句执行之后,v_sal就有值了。


dbms_output.put_line('员工编号为:'||v_empno||'的薪资为:'||v_sal);

END;

/

Oracle数据库工程师技术实战索引和PLSQL_sql_39


注意:调用的时候,参数要与定义的参数的顺序和类型一致.


debug测试​

【扩展】

如何直接测试存储(相当于debug)测试:

Oracle数据库工程师技术实战索引和PLSQL_数据_40


Oracle数据库工程师技术实战索引和PLSQL_赋值_41


给用户进行调试权限:

grant debug any procedure to 当前用户;
grant debug connect session to 当前用户;

小结:​

存储过程作用:主要用来执行一段程序。

  1. 在开发程序中,了一个特定的业务功能,会向数据库进行多次连接关闭(连接和关闭是很耗费资源)就需要对数据库进行多次I/O读写,性能比较低。如果把这些业务到PLSQL中应用程序中只需要调用PLSQL可以做到连接关闭一次数据库就可以实现我们的业务,可以大大提高效率.
  2. ORACLE官方给的建议:够让数据库操作的不要放在程序中数据库中实基本上不会出现错误,在程序中操作可以会存在错误.(如果在数据库中操作数据,可以有一定的日志恢复等功能.)


三种存储

  • 无参参数:只要用来做数据处理的。存储内部写一些处理数据的逻辑。
  • 带输入参数:数据处理时,可以针对输入参数的值来进行判断处理。
  • 带输入输出参数:一般用来传入一个参数值,我想经过数据库复杂逻辑处理后,得到我想要的值然后输出给我。


触发器(trigger) ​

概念和作用​

数据库触发器是一个与表相关联的、存储的PL/SQL程序。每当一个特定的数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle自动地执行触发器中定义的语句序列。

解释:

首先,它也是一段plsql程序。

然后,它是来触发与表数据操作相关的(insert,update,delete)。

然后,在进行表数据操作的时候,会自动触发执行的一段程序。


换句话说:触发器就是在执行某个操作(增删改)的时候触发一个动作(一段程序)


语法​

创建触发器语法:

CREATE [or REPLACE] TRIGGER 触发器名

{BEFORE | AFTER}

{DELETE | INSERT | UPDATE [OF 列名]}

ON 表名

[FOR EACH ROW [WHEN(条件) ] ]

PLSQL 块

解释:

Oracle数据库工程师技术实战索引和PLSQL_赋值_42



第一个触发器​

【示例】

-每dept表中添加一位新部门时,打印”成功插入新部门

打开窗口:

Oracle数据库工程师技术实战索引和PLSQL_赋值_43


createorreplacetriggertri_adddept

AFTERINSERTon dept

declare

begin

dbms_output.put_line('插入了新部门');

end ;

Oracle数据库工程师技术实战索引和PLSQL_数据_44


--测试哈 重开一个窗口测试

SELECT * FROM dept;

INSERTINTO dept VALUES(80,'zz1','上海');

SELECT * FROM dept;



触发的类型​

  • 语句级触发器(表级触发器)在指定的操作语句操作之前或之后执行一次,不管这条语句影响了多少行 。
  • 行级触发器(FOR EACH ROW)

触发语句作用的每一条记录都被触发。在行级触发器中使用old和new伪记录变量, 识别值的状态。


语句级触发器和行级触发器的区别​

【示例】目标:演示语句级触发器和行级触发器的区别

复制出来一张表depttemp,分别建立语句级和行级触发器,然后进行批量插入操作测试。

CREATETABLE depttemp ASSELECT * FROM dept WHERE1<>1;

SELECT * FROM depttemp;


两个触发器编写:

--语句级别

createorreplacetriggertri_adddepttemp_yuju

afterinserton depttemp

declare

begin--plsql语句

dbms_output.put_line('成功插入了一个部门:语句级触发器触发了。。:');

end tri_adddepttemp_yuju;


--行级别:

createorreplacetrigger tri_adddepttemp_hangji

afterinserton depttemp

foreachrow--行级触发器

declare

begin--plsql语句

dbms_output.put_line('成功插入了一个部门:行级触发器触发了。。:');

end tri_adddepttemp_hangji;



批量插入数据测试:

--先建立两种触发器

--批量插入数据

INSERTINTO depttemp SELECT * FROM dept;


Oracle数据库工程师技术实战索引和PLSQL_sql_45


表级触发器和行级触发器区别:

  1. 在语法上,行级触发器就多了一句话:for each row
  2. 在表现上,行级触发器,在每一行的数据进行操作的时候都会触发

语句级触发器,对表的一个完整操作才会触发一次

简单的说:行级触发器,是对应行操作的;级触发器,是对应表操作的。

行级别触发器的伪记录变量​

Oracle数据库工程师技术实战索引和PLSQL_数据_46


:new代表操作之后的数据,只出现在INSERT/UPDATE中,

:old代表操作(cud)之前的那条数据,出现在UPDATE/DELETE,

INSERT时:NEW表示新插入的行数据,UPDATE时:NEW表示要替换的新数据,:old表示要被更改的原来数据,DELETE时:old表示要被删除的数据。


【示例】

涨工资:涨后的工资不能少于涨前的工资

分析:行级触发器,数据确认示例--行级触发器


--涨工资:涨后的工资不能少于涨前的工资

createorreplacetrigger tri_checkempsal

BEFOREUPDATEON emp--更新之前拦截触发

foreachrow--行级触发器

declare

BEGIN

--如果涨后小于涨前,则,终止更新操作

IF :new.Sal<:old.Sal THEN

--终止程序继续运行,也就终止了更新操作了。随便写

raise_application_error(-20008,'涨后的工资不能少于涨前的工资!!涨前的工资:'||:old.Sal||',涨后的工资:'||:new.sal);

--相当于抛出异常(throw),(使用了oracle内置的一个函数来抛出异常)

ENDIF;

end tri_checkempsal;


Oracle数据库工程师技术实战索引和PLSQL_sql_47


测试:

Oracle数据库工程师技术实战索引和PLSQL_赋值_48


触发器的应用场景​

Oracle数据库工程师技术实战索引和PLSQL_sql_49


【示例】

数据的备份:

业务的原理:在更新或者删除数据的时候,将旧的数据备份出来到另外一张表中。

建立一张备份表:

Oracle数据库工程师技术实战索引和PLSQL_数据_50

Oracle数据库工程师技术实战索引和PLSQL_赋值_51


目标:在更新dept的时候,进行触发该动作。(备份数据)


--自动备份数据

CREATEORREPLACETRIGGER tri_autobakdept

BEFORE

UPDATE

ON dept

FOREACHROW--行级触发器

BEGIN

--备份:

INSERTINTO DEPTBAK VALUES(seq_ID.nextval,:OLD.DEPTNO,:old.Dname,:old.Loc,

:new.Deptno,:new.Dname,:new.Loc,SYSDATE);

END;

测试:

SELECT * FROM deptbak;


UPDATE dept SET dname = dname||'1';



删除备份​

Oracle数据库工程师技术实战索引和PLSQL_sql_52


Oracle数据库工程师技术实战索引和PLSQL_sql_53



但是要注意:触发器会引起锁,降低效率!使用时要慎重。如无必要,尽量不要使用触发器。


行级触发器会引发行级锁(锁行数据)

语句级触发器可能会引起表级锁(锁表)

数据的备份还原​

数据的备份(导出)

使用plsqlDeveloper工具:

Oracle数据库工程师技术实战索引和PLSQL_sql_54




目标:导出emp表中的10号部门的数据 如果不给出条件导出的是所有

Oracle数据库工程师技术实战索引和PLSQL_赋值_55


你可以使用ctrl或shilft键进行选择。


Oracle数据库工程师技术实战索引和PLSQL_sql_56



导入数据:

Oracle数据库工程师技术实战索引和PLSQL_sql_57



用途:一般如果需要服务器上的某个表的数据,可以用这种方法进行传输。


【导入的前提】

先建立用户,然后在用户下面导入数据。

Oracle数据库工程师技术实战索引和PLSQL_数据_58



SQL语句的导出。(表对象转换为SQL)


问题来了:

语句怎么弄?如果一条数据,你手动写没问题,那么有100条数据。

想想:起始测试环境下数据库已经有这些数据了,能否将这些数据转换成insert语句。


Oracle数据库工程师技术实战索引和PLSQL_数据_59


Oracle数据库工程师技术实战索引和PLSQL_sql_60


Oracle数据库工程师技术实战索引和PLSQL_赋值_61




【扩展】

drop table DEPT cascade constraints; 不管dept是否有外表关联,都可以删除。(会自动解除关系)

Oracle数据库工程师技术实战索引和PLSQL_赋值_62




PDE格式,这是PLSQLdeveloper这个oracle数据库管理工具特有的格式,只能通过PLSQL developer导出数据产生,也只能通过PLSQL developer将其中数据导入到数据库。文件也不能通过编辑器查看和编辑。不过这种方式不受源数据表空间、用户名等约束,且数据量更小


格式,顾名思义,sql格式的文件就是一个sql的运行脚本文件,这决定了这个文件可以在几乎所有的主流数据库运行,还可以在文本编辑器上查看修改,通用性比较好,但是正因为需通用于大部分主流数据库,所以它的sql文件里,只能保存通用类型









举报

相关推荐

0 条评论