oracle-plsql

在这里插入图片描述
PL/SQL是 Procedure Language & Structured Query Language 的缩写
辅助命令:
set serveroutput on –打开日志输出
clear –清屏

sql

设置

SQL> set timing on;          //设置显示“已用时间:XXXX”
SQL> set autotrace on-;    //设置允许对执行的sql进行分析
SQL> set trimout on; //去除标准输出每行的拖尾空格,缺省为off
SQL> set trimspool on; //去除重定向(spool)输出每行的拖尾空格,缺省为off
SQL> set echo on               //设置运行命令是是否显示语句
SQL> set echo off; //显示start启动的脚本中的每个sql命令,缺省为on
SQL> set feedback on;       //设置显示“已选择XX行”
SQL> set feedback off;      //回显本次sql命令处理的记录条数,缺省为on
SQL> set colsep' '; //输出分隔符
SQL> set heading off;    //输出域标题,缺省为on
SQL> set pagesize 0;     //输出每页行数,缺省为24,为了避免分页,可设定为0。
SQL> set linesize 80;     //输出一行字符个数,缺省为80
SQL> set numwidth 12;     //输出number类型域长度,缺省为10
SQL> set termout off;    //显示脚本中的命令的执行结果,缺省为on
SQL> set serveroutput on;  //设置允许显示输出类似dbms_output
SQL> set verify off         //可以关闭和打开提示确认信息old 1和new 1的显示.

准备

--删除口令有效期限制
alter profile default limit PASSWORD_LIFE_TIME unlimited;
Linux下使用SQL*PLUS发现无法像bush一样上下翻页,也不能退格,只要安装rlwrap即可
# rpm -ivh rlwrap-0.42-1.el6.x86_64.rpm
# vi ~oracle/.bashrc
alias sqlplus='rlwrap sqlplus'
alias rman='rlwrap rman'

sql基础

DML 数据操作: insert update delete merge	  
MERGE从一个表中提取的数据 ,同步到另外一个表中 ,实现在线更新
DDL 数据定义:create alter drop rename truncate comment
DCL 数据库控制:grant revoke 
TCL 事务控制:commint rollback savepoing

DUMP(expr[,return_fmt[,start_position][,length]])  
    基本参数为4个,最少可以填的参数是0个。当完全没有参数时,直接返回null。另外3个参数也都
    有各自的默认值:
      expr:这个参数是要进行分析的表达式(数字或字符串等,可以是各个类型的值)
      return_fmt:指返回参数的格式,有5种用法:
                 1)8:以8进制返回结果的值
                 2)10:以10进制返回结果的值(默认)
                 3)16:以16进制返回结果的值
                 4)17:以单字符的形式返回结果的值
                 5)1000:以上4种加上1000,表示在返回值中加上当前字符集
      start_position:开始进行返回的字符位置
      length:需要返回的字符长度
 eg: select dump('abc') from dual;

--字符串拼接
SELECT FIRST_NAME||' '|| LAST_NAME FROM HR.EMPLOYEES;
--通配符:
select last_name, job_id from HR.employees where job_id like '%\_MAN' escape '\';
--单引号的处理
SELECT 'I'' am teacher' from dual;
SELECT q'[I'm teacher]' from dual;

SELECT SESSIONTIMEZONE, CURRENT_DATE FROM DUAL;
--修改时区
ALTER SESSION SET TIME_ZONE='+9:00'
--用户级别(修改时间格式)
ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy-mm-dd hh24:mi:ss';
--库级别(修改时间格式)
ALTER SYSREM SET NLS_DATE_FORMAT='yyyy-mm-dd hh24:mi:ss';
--多少月
select MONTHS_BETWEEN(sysdate,hire_date) from hr.employees ;

--随机数
/*1)'u', 'U' - returning string in uppercase alpha characters
2)'l', 'L' - returning string in lowercase alpha characters
3)'a', 'A' - returning string in mixed case alpha characters
4)'x', 'X' - returning string in uppercase alpha-numeric characters
5)'p', 'P' - returning string in any printable characters.
6)Otherwise the returning string is in uppercase alpha characters.*/
--随机生成8位大写字母
select dbms_random.string('u',8) x from dual;
select dbms_random.string('U',8) x from dual;
--随机生成8位小写字母
select dbms_random.string('l',8) x from dual;
select dbms_random.string('L',8) x from dual;
--随机生成8位小小写混合字母
select dbms_random.string('a',8) x from dual;
select dbms_random.string('A',8) x from dual;
--随机生成8位大写字母和数字
select dbms_random.string('x',8) x from dual;
select dbms_random.string('X',8) x from dual;
--随机生成8位任意符号
select dbms_random.string('p',8) x from dual;
select dbms_random.string('P',8) x from dual;
--返回的内容仍将是大写字母
select dbms_random.string('2',8) x from dual;

用户权限

--用户(创建、删除、锁定、解锁)
create user user_name identified by password;
drop user user_name cascade;
alter user user_name account LOCK/UNLOCK
数据库的权限分为:
1.系统权限
大部分是针对对象的创建,删除,修改,审计等等的操作
--查看系统都具备哪些权限
SELECT PRIVILEGE FROM DBA_SYS_PRIVS;
--当前会话权限
select * from session_privs; 
2.对象权限
授予特定用户对特定对象的权限
	特定对象:表、视图、序列、过程、函数、程序包上。
角色
	系统中有数百个权限 我们不便于管理
	于是oracle对很多需求的权限定义成了角色的模式 来方便我们管理
	角色就是一组权限的集合
	--系统角色
select distinct granted_role from dba_role_privs;
--查看角色的权限
select grantee ,privilege from dba_sys_privs  where grantee='RESOURCE';
-- 权限 赋予、收回
--with admin option 权限回收无级联 适用系统权限和角色
--with grant option 权限回收有级联 适用对象权限
grant  connect,resource to u1;
revoke connect,resource from u1;

数据字典和性能视图

数据字典:
ORACLE会对系统的操作及相关的信息记录在系统的只读表里,这类表叫基表基表过于复杂,oracle在此基础之上又建立了视图和同义词,供DBA查询更人性化的数据这类视图和同义词我们称之为数据字典. 它存储的是不经常改动的数据.
分为:
数据字典基表 ( ) : c r e a t e d a t a b a s e s q l . b s q o b j 结尾): 在create database 的时候由sql.bsq自动建立 存储了数据库的描述信息比如 obj user$
数据字典视图: 由catalog.sql脚本建立 分别以dba_ all_ user_开头
数据字典命名包含图
在这里插入图片描述
DBA: 所有的object
ALL: 当前用户可以访问的object
USERS: 当前用户的object
动态性能视图:
oracle内存在运行中时刻都在变化,这些变化的数据寄存于动态性能表(内存表,固定表)中,随数据库启动而建立,随数据库运行而增加内容动态性能表也过于复杂,oracle在此基础之上又建立了视图和同义词,用于DBA判断系统的性能状态信息 .这类视图和同义词我们称之为动态性能视图. 它储存的是时刻改变的数据.

序列

语法
	CREATE SEQUENCE seq_name
	[INCREMENT BY n]
	[START WITH n]
	[{MAXVALUE N | NOMAXVALUE}]
	[{MINVALUE N | NOMINVALUE}]
	[{CYCLE | NOCYCLE}]
	[{CACHE N|NOCACHE}];
INCREMENT BY 	N表示步长
START WITH N	    N表示初始值
[NO]MAXVALUE N	N表示有没有最大值 最大值是多少 NOMINVALUE选项最大值时10^27
[NO]MINVALUE N  N最小值
CYCLE		达到最大是否循环回到初始值
[NO]CACHE	就是你每次在内存里预保存多少个值 免得每次都要获取 浪费资源 一次获取批量存在内存中
取值方法
	NEXTVAL 返回下一个值
	--next value
	CURRVAL 返回当前值 
	-- current value

约束

约束的五种类型
		非空	not null
		唯一	unique
		检测	check
		主键	primary key
		外键	foreign key

索引

INDEX 索引
	一种SCHEMA对象 和表不在同一个命名空间 所以可以和表重名
	通过行的指针(ROWID)来加速获取数据
	能用很少的磁盘IO快速定位数据
	索引跟表是独立的对象,逻辑上关联
	被ORACLE自动维护 (不完全这样,有的时候索引会失效,我们要rebuilt)
索引按类型划分
	B-TREE
		普通单键B-TREE
		复合键索引
多列当表达式的索引
		好处是如果你想查的列全部在索引中,就不用回表取数据了.
		这样会大量的减少IO
		一般都会把重复值多的列放前面 可以通过count(distinct col)计算哪列重复值少
		建立的索引应该和where条件中使用的列的顺序一致
		如果where col1='A' AND COL2='B' and col3='C' 建立了复合索引(col1,col2,col3)
		而使用where COL2='B' 是不走索引的(当然这要看列中的数据是否被分析,也就是CBO是否能精确的计算)
		CBO产生执行计划的分析依据就以表内数据分布情况.
		如果不分析表,CBO就获取不到正确的分析样本 就可能产生错误的执行计划(详细的调优时再说明)
	create index XXX on table_name(col1,col2...);

何时建索引
索引多并不意味着性能好,索引对查询有利 对DML是有负担的.

1.一个字段包含一个较大范围的值,也就是说重复率比较小,就是所谓的高基数列
	2.一个列包含大量的NULL值
	3.频繁在where子句中出现的列 我们要关注是否建立索引
	4.大表的外键列 需要建立索引 因为主键值的DML操作会间接的去外键中验证是否在外键列引用外键列此时没索引 就要全表扫描 所以一个主键只有几条记录 外键无索引一个DML可能会几个小时...

普通索引的创建
自动创建
建立主键和唯一约束时自动创建唯一索引
手动创建
CREATE INDEX index_name ON table(COL1[COL2,COL3…]);
多个column代表复合索引
合并coalesce
不释放索引结构占据的空间(索引段)
即使有事务也可以合并
只合并枝干内的叶子,不同分支的叶子会独立合并
合并不改变索引的结构 对应第一点:结构在空间在
重构rebuild
删旧建新 一切都是新的
但只能在没事务的情况下重构
删除索引 drop index index_name;
删除表会级联删除表上索引
删除表到回收站后 索引也会改名 恢复表后 索引依旧保持回收站中的名字 需手动改名
alter index “BIN$pETn2AVtm9PgQAoKFAoMAQ==$0” rename to ind_ti_empno;

oracle提供的锁有三类
	DML锁
	DDL锁
	LATCH
	【10.2引入metux,用来代替部分latch。】
锁的信息可以通过如下性能视图查得
	v$lock
	v$locked_object
	dba_blockers
	dba_waiters
	dba_dml_locks
	dba_ddl_locks
--查询锁
select sess.sid, 
    sess.serial#, 
    lo.oracle_username, 
    lo.os_user_name, 
    ao.object_name, 
    lo.locked_mode 
    from v$locked_object lo, 
    dba_objects ao, 
    v$session sess 
where ao.object_id = lo.object_id and lo.session_id = sess.sid;
--解锁
alter system kill session 'sid,serial#';

快速处理(直接执行查询出来的语句:)
select 'alter system kill session '''||sess.sid||','||sess.serial#||''';'
   ||'--uplock table:'||lo.oracle_username||'->'||lo.os_user_name||'->'||ao.object_name||'->'||lo.locked_mode
  from v$locked_object lo,  dba_objects ao,   v$session sess 
where ao.object_id = lo.object_id and lo.session_id = sess.sid;

临时表

临时表的分类:
ORACLE根据你创建临时表时指定的参数
事务级 On Commit Delete Rows
数据在 Transaction 期间有效
一旦COMMIT后,rollback,断开连接,数据就被自动 TRUNCATE 掉
会话级 On Commit Preserve Rows
数据在 Session 期间有效
一旦关闭了Session 或 Log Off 后,数据就被 ORACLE 自动 Truncate 掉

外部表

外部表
表数据存放在OS级别的文件中.通过数据库目录做授权oracle用户使用
只读访问.不能修改.
外部表只是描述了数据引入读取格式.将其描述写入了数据字典里.
–查看数据库目录

select * from dba_directories;

在这里插入图片描述

创建目录(会在 plsql所在端 创建):
-- for windows
$ mkdir D:\DataBase\app\uis\product\liuli;
--for linux
! mkdir D:\DataBase\app\uis\product\liuli
创建外部表:

表压缩

基本和高级行压缩
基本表压缩:
这种类型的压缩旨在用于批量加载操作。数据库不会压缩使用传统DML修改的数据。您必须使用直接路径加载,ALTER TABLE . . . MOVE操作或联机表重新定义来实现基本压缩。
高级行压缩:
这种类型的压缩旨在用于OLTP应用程序并压缩由任何SQL操作操纵的数据。
ALTER TABLE oe.orders COMPRESS FOR OLTP;
混合列压缩的类型
仓库压缩:
这种压缩类型经过优化以节省存储空间,适用于数据仓库应用程序。
在线档案压缩:
此类压缩针对最大压缩级别进行了优化,适用于不会更改的历史数据和数据。

sqlldr

从OS文件中批量的导入数据时使用

隔离级别

Oracle数据库提供的ANSI / ISO SQL隔离级别
在这里插入图片描述

匿名块接口和组成元素

PL/SQL程序由三个块组成,即声明部分、执行部分、异常处理部分。
PL/SQL块的结构如下:
DECLARE  
/* 声明部分: 在此声明PL/SQL用到的变量,类型及游标,以及局部的存储过程和函数 */
BEGIN
    /*  执行部分:  过程及SQL 语句  , 即程序的主要部分  */
EXCEPTION
   /* 执行异常部分: 错误处理  */
END;
/
PL/SQL块可以分为三类:
1.	无名块:动态构造,只能执行一次。
2.	子程序:存储在数据库中的存储过程(procedure)、函数(function)及包(package)等。当在数据库上建立好后可以在其它程序中调用它们。
3.	触发器(trigger):当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。

%TYPE

%TYPE 操作可以将一个变量的数据类型和表中的某一列的数据类型绑定为一致状态;
declare
 v_ename scott.emp.ename%type;
 v_sal scott.emp.sal%type;
begin
 select ename,sal into v_ename,v_sal from scott.emp where empno=7839;
 dbms_output.put_line(chr(10)||v_ename||' '||v_sal); 
end;

数组:

declare 
 type no_list is varray(3) of number;
 v_nolist  no_list:=no_list(1190,2010,1995);
begin
    dbms_output.put_line('no_list 2 is:'||v_nolist(2));
 end;
/

记录(复合数据类型):

declare
type emp_record_type is record
(
     ename varchar(10),
     job varchar(10)
);
emp_record emp_record_type;
begin
  emp_record.ename:='liuli';
  emp_record.job:='IT';
  dbms_output.put_line( emp_record.ename||' job is '||emp_record.job);
end;
/

%ROWTYPE

%ROWTYPE 操作可以将一个RECORD的结构和某一张表的结构型绑定为一致状态;
也可以将一个RECORD的结构和某一个已经声明过的cursor变量的结构绑定为一致状态;
使用%ROWTYPE特性的优点在于:
所引用的数据库中列的个数和数据类型可以不必知道;
所引用的数据库中列的个数和数据类型可以实时改变。
declare
    v_empno scott.emp.empno%type:=&no;
    rec scott.emp%rowtype;
begin
  select * into rec from scott.emp where empno=v_empno;
  dbms_output.put_line('name is:'||rec.ename||' salary:'||rec.sal);
end;

LOB类型

BFILE (Movie)
    存放大的外部二进制数据对象,这些数据文件不放在数据库里,而是放在操作系统的某个目录里,数据库的表里
只记录该二进制文件在操作系统中的绝对路径的指针。
BLOB(Photo)
    存储大的二进制数据类型。变量存储大的二进制对象的位置。大二进制对象的大小<=4GB。
CLOB(Book)
    存储大的字符数据类型。每个变量存储大字符对象的位置,该位置指到大字符数据块。大字符对象的大小<=4GB。
NCLOB
    存储大的NCHAR字符数据类型。每个变量存储大字符对象的位置,该位置指到大字符数据块。大字符对象的大小
      <=4GB。

索引表(index-table)

declare 
 type emp_table_type is table of varchar2(20) index by binary_integer;
 emp_table emp_table_type;
begin
  emp_table(0) :='Alex';
  emp_table(-1) :='X1';
  emp_table(2) :='hello';
  dbms_output.put_line('index 0 : '||emp_table(0));
  dbms_output.put_line('index -1 : '||emp_table(-1));
  dbms_output.put_line('index 2 : '||emp_table(2));
end;
/
使用集合的方式操作:
declare
 type emp_table_type is table of varchar2(10) index by varchar2(10);
 emp_table emp_table_type;
 begin
   emp_table('A') := 'aVALUE';
   emp_table('B') := 'bVALUE';
   emp_table('C') := 'cVALUE';
   dbms_output.put_line('元素个数:'|| emp_table.count);
   dbms_output.put_line('第一个元素:'||emp_table.first);
   dbms_output.put_line('最后一个元素:'||emp_table.last);
   dbms_output.put_line('B前面的元素:'||emp_table.prior('B'));
   dbms_output.put_line('A后面的元素:'||emp_table.next('A'));
   if emp_table.exists('C') then
     dbms_output.put_line('Index C is:'|| emp_table('C'));
   end if;
 end;
/
PL/SQL表+record
declare
type dept_table_type is table of scott.dept%rowtype index by binary_integer;
dept_table dept_table_type;
v_count number(2):=4;
begin
 for int in 1 .. v_count loop 
   select * into dept_table(int) from scott.dept where deptno= int*10;
 end loop;
 for int in dept_table.first .. dept_table.last loop
   dbms_output.put_line('Department name: '|| dept_table(int).dname);
 end loop;
end;
/

绑定变量

绑定变量属于非PL/SQL变量,是在主机环境中或宿主语言中定义的变量。
所以变量获得的值不会因为PL/SQL块的结束而释放,可以将PL/SQL块的取值传到语句块的外部。为了在Sql*plus 环境中声明绑定变量,可以使用命令VARIABLE。
variable g_message varchar2(30)
begin
  :g_message := 'my first variable';
end;
/
print g_message

控制结构

if

--empno = 7839  7369
declare
 v_empno scott.emp.empno%type :=&empno;
 v_salary scott.emp.sal%type;
 v_comment varchar2(35);
begin
  select sal into v_salary from scott.emp where empno = v_empno;
  if v_salary <1500 then
     v_comment:= 'Fairly less';
  elsif v_salary<300 then
     v_comment:= 'A little more';
  else
     v_comment:= 'Lots of salary';
  end if;
   dbms_output.put_line(v_comment);
  exception 
    when no_data_found then
      dbms_output.put_line(sqlcode||sqlerrm);
 
end;
/

case

define p_grade='a'
declare 
   v_grade char(1) := upper('&p_grade');
   v_appraisal varchar2(20);
begin
  v_appraisal:= 
    case v_grade
       when 'A' then 'excellent'
       when 'B' then 'very good'
       when 'C' then 'good'
       else 'no such grade!'  
    end;
      dbms_output.put_line ('grade: '|| v_grade || ' appraisal ' || v_appraisal);
end;
/

goto

declare
v_counter number :=1;
begin
 loop
   dbms_output.put_line('in loop V_counter current value:'||V_counter);
   v_counter :=v_counter +1;
   if v_counter >10 then
      goto l_ENDofLOOP;
   end if;
 end loop; 
   <<l_ENDofLOOP>>
    dbms_output.put_line('end loop V_counter current value:'||V_counter);
end;
/

while

--  *不能用i++
declare 
 i integer :=1;
 begin
   loop
     dbms_output.put_line(i);
     i :=i+1;
     exit when i>10;
   end loop;
 end;
/

declare 
 i integer :=1;
 begin
  while i<=10 loop
    dbms_output.put_line(i);
    i := i+1;
  end loop;
 end;
/

begin
  for i in 1..10 loop --for i in reverse 1..10 loop  循环索引倒排
    dbms_output.put_line(i);
  end loop;
end;
/

null

可以用 null 语句来说明“不用做任何事情”的意思,相当于一个占位符,可以使某些语句变得
有意义,提高程序的可读性。

游标

显式游标处理需要4个步骤:

定义游标:就是定义一个游标名,以及与其相对应的SELECT 语句。
CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;
打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有FOR UPDATE选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。
OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];
获取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中,每当fetch操作从游标中取出一行数据游标上下文中都将丢弃这一行数据,直到所有行都从上下文中被取出这块内存区域中的数据将都被丢弃,但内存空间
FETCH cursor_name INTO {variable_list | record_variable };
关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。但关闭后的游标不能再一次被关闭否则将会报错。
CLOSE cursor_name;
注:定义的游标时的查询语句中不能有INTO 子句。
游标属性:游标属性是返回状态和游标取值情况的变量,由系统维护,显示游标有下面四种属性:
%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为TRUE;
%NOTFOUND 布尔型属性,与%FOUND相反;
%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
使用格式如下:
C1%rowcount -->其中c1是用户自定义的显示游标变量的名字。
SQL%rowcount -->其中SQL是系统定义的隐式游标。

declare 
  v_empno scott.emp.empno%type;
  v_ename scott.emp.ename%type;
  cursor emp_cursor is select empno,ename from scott.emp;--声明
begin
     open emp_cursor;--打开
     loop
       fetch emp_cursor into v_empno,v_ename; -- 获取
       exit when emp_cursor%rowcount>5 or emp_cursor%notfound;
       dbms_output.put_line('获取的数据'||v_empno ||v_ename);
     end loop;
     close emp_cursor;--关闭
end;
/

declare
cursor emp_cursor is select rownum,empno,ename from scott.emp;--声明
begin
for emp_record in emp_cursor loop-- 隐试打开游标
  exit when emp_cursor%rowcount>5;  
      dbms_output.put_line(emp_record.rownum||' '||
                           emp_record.empno||' '||
                           emp_record.ename);
  end loop;--隐试关闭
end;
/

--省略游标定义
begin
  for r in(select ename from scott.emp) 
  loop--隐式打开隐式获取
    dbms_output.put_line(r.ename);
     --默认的循环退出条件为notfound为true
  end loop;
end;
/

--带参数的游标
declare
cursor c1 (p_deptno number,p_job varchar2)
is 
select empno,ename from scott.emp 
where  deptno=p_deptno and job=p_job;
begin
  dbms_output.put_line('first fetch cursor!');
  for r_c1 in c1(10,'MANAGER') loop
     dbms_output.put_line(r_c1.empno||' '||r_c1.ename); 
  end loop;
     dbms_output.put_line('second fetch cursor!');
   for r_c1 in c1(20,'MANAGER') loop
     dbms_output.put_line(r_c1.empno||' '||r_c1.ename); 
  end loop;
end;
/

隐式游标

对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,这些由系统隐含创建的游标称为隐式游标,隐式游标的名字为SQL,这是由ORACLE 系统定义的。对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。
SQL%ROWCOUNT
在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功, SQL%ROWCOUNT的值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.
SQL%ISOPEN
是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%ISOPEN总是FALSE,这是因为隐式游标在DML语句执行时打开,结束时就立即关闭。
SQL%FOUND
布尔型属性,当最近一次读记录时成功返回,则值为TRUE;
在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是:
. TRUE :INSERT 成功
. TRUE DELETE和UPDATE,至少有一行被DELETE或UPDATE.
. TRUE :SELECT INTO至少返回一行

异常错误处理

oracle有三种类型的异常处理:
1. 预定义 ( Predefined )异常
ORACLE预定义的异常情况大约有20几个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。
2. 非预定义 ( Predefined )异常
即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。
3. 用户定义(User_define) 错误
程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序
中将其引发。

SQLCODE 返回错误代码数字。
SQLERRM 返回错误信息。

预定义异常

常用预定义异常:
TOO_MANY_ROWS : SELECT INTO返回多行
INVALID_CURSOR :非法指针操作(关闭已经关闭的游标)
ZERO_DIVIDE :除数等于零
DUP_VAL_ON_INDEX :违反唯一性约束
ACCESS_INTO_NULL: 未定义对象
CASE_NOT_FOUND: CASE 中若未包含相应的 WHEN ,并且没有设置 ELSE 时
COLLECTION_IS_NULL: 集合元素未初始化
CURSER_ALREADY_OPEN: 游标已经打开
DUP_VAL_ON_INDEX: 唯一索引对应的列上有重复的值
INVALID_NUMBER: 内嵌的 SQL 语句不能将字符转换为数字
NO_DATA_FOUND: 使用 select into 未返回行,或应用索引表未初始化的元素时
SUBSCRIPT_BEYOND_COUNT:元素下标超过嵌套表或 VARRAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT: 使用嵌套表或 VARRAY 时,将下标指定为负数
VALUE_ERROR: 赋值时,变量长度不足以容纳实际数据
LOGIN_DENIED: PL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码
NOT_LOGGED_ON: PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据
PROGRAM_ERROR: PL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包
ROWTYPE_MISMATCH: 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容
SELF_IS_NULL: 使用对象类型时,在 null 对象上调用对象方法
STORAGE_ERROR: 运行 PL/SQL 时,超出内存空间
SYS_INVALID_ID: 无效的 ROWID 字符串
TIMEOUT_ON_RESOURCE: Oracle 在等待资源时超时
Transaction-backed-out : 由于发生死锁事务被撤消

set serveroutput on
clear;
declare
v1 scott.emp.sal%type;
begin
 select sal into v1 from scott.emp where empno=7777;
 exception
   when too_many_rows then
     dbms_output.put_line('more person !');
   when no_data_found then
     dbms_output.put_line('no rows selectde');
   when others then --通用异常处理
     dbms_output.put_line('other error'|| sqlerrm); 
end;
/

非预定义异常

declare
fk_error exception;--声明异常
pragma exception_init(fk_error ,-2292);--使用编译指示器将异常名称和oracle的错误代码绑定
begin
 delete scott.dept;----oracle自动传播错误(fk_error)
 dbms_output.put_line('ok');
 exception
   when fk_error then--捕获非预定义异常
    dbms_output.put_line('my error:'||sqlcode||sqlerrm);          
end;
/

用户自定义异常

有1000个错误编码是oracle没有使用的,
编号从ORA-20000 ~ ORA-20999 ,这些错误编码是oracle留给程序员使用的,用户定义的异常就是将将自己的异常和这1000个错误编码相绑定,而这些错误编码oracle是不会传播的,也就是说oracle的从来不会自动抛出编码为ORA-20000的错误如果我们的异常与ORA-20000相关联了那么我们必须自己传播这个错误,错误被传播的同时也会将自定义异常一起传播出来,然后就可以在exception子句中进行捕获了,通过这种手段我们可以将任何一种逻辑操作当作oracle的错误向外传播。
declare
v_sal number not null :=&p_sql;
my_error exception;
pragma exception_init(my_error,-20001);---编译指示,将命名的异常与ORACLE ERROR关联
begin
  if v_sal <2000 then
    raise_application_error(-20001,'my error1');--将异常传送的环境
  else
    dbms_output.put_line('sal is:'||v_sal);
  end if;
  exception
    when my_error then
      dbms_output.put_line('get my error:'||sqlerrm);   
end;
/

函数/存储过程

函数

形式参数是命名块的头部引入的参数,可以传值到代码内部,也可一保存代码工作后的返回值。
形式参数有三种类型,导入型(in):传入值,导出型(out):传出值,导入导出型(in out):传递变量。
in类型的形式参数是代码工作时要求输入的值
out类型的形式参数是代码工作后的返回值。
in out类型的形式参数在代码工作前带一个值传入代码,在代码工作结束后再将一个值返回到代码外部。
--函数
create or replace function get_subtotal_salary(
 dept_no number,
 emp_count out number
)return number is v_sum number;
begin
 select sum(sal),count(*) into v_sum ,emp_count from scott.emp where deptno=dept_no;
 return v_sum;
exception
  when others then
    dbms_output.put_line(sqlcode||sqlerrm);
end get_subtotal_salary;
--调用  7369
declare
v1 number;
v2 number;
v3 number:=&p_deptno;
begin
 v2:=get_subtotal_salary(v3,v1);
 dbms_output.put_line(v3||' 部门员工总数:  '||v1||'  部门总工资: '||v2);
end;
/
--当前用户下有哪些function
select object_name,object_type,status from user_objects where object_type='FUNCTION';
--查看function的源代码
select text from user_source where lower(name)='function_name';
--删除函数
drop function function_name; 

过程

存储过程可以没有返回值,如果存储需要返回一个值可以借助out类型的形式参数。
create or replace procedure raise_salary
(p_empno in scott.emp.empno%type)
is
begin
  dbms_output.put_line('you empno is:'|| p_empno);
end raise_salary;
--使用execute 命令调用
execute raise_salary(12345); 
--匿名块执行
declare
begin
   raise_salary(12345);
end;
/

--导出型形式参数(out类型)
create or replace procedure query_emp
(p_id in scott.emp.empno%type,
 p_name out scott.emp.ename%type,
 p_salary out scott.emp.sal%type,
 p_comm out scott.emp.comm%type
)
is 
begin
  select ename,sal,comm into p_name,p_salary,p_comm from scott.emp where empno=p_id;
end query_emp;
/
--调用
variable g_name varchar2(25)
variable g_sal number
variable g_comm number
execute query_emp(7839, :g_name, :g_sal, :g_comm);

本地化

在PL/SQL 程序中还可以在块内建立本地函数和过程,这些函数和过程不存储在数据库中,但可以在创建它们的PL/SQL 程序中被重复调用。本地函数和过程在PL/SQL 块的声明部分定义,它们的语法格式与存储函数和过程相同,但不能使用CREATE OR REPLACE 关键字。
-	函数、过程 名称不区分大小写
declare 
v_num number;
v_sum number(8,2);
procedure proc_demo
  (dept_no NUMBER DEFAULT 10,
		sal_sum OUT NUMBER,
		emp_count OUT NUMBER)
    is begin
    SELECT SUM(sal), COUNT(*) INTO sal_sum, emp_count FROM scott.emp WHERE deptno=dept_no;
    exception 
      when others then
        dbms_output.put_line(sqlerrm);
end proc_demo;

begin
  Proc_demo(30, v_sum, v_num);
  dbms_output.put_line('30号部门工资总和:'||v_sum||',人数:'||v_num);
end;
/

自治事务

Autonomous_transaction
默认情况下,子程序的事务处理语句(commit; & rollback;)会结束父程序的事务,如果子程序使用自治事务那么子程序的事务处理语句只在子程序内部有效
create or replace procedure p1
(v_sal scott.emp.sal%type,v_empno scott.emp.empno%type)
is 
 pragma autonomous_transaction;--自己处理事务
begin
  update scott.emp set sal =v_sal where empno=v_empno;
end p1;
/

动态SQL技术

就是将ddl语句以字符串的形式出现在程序代码中,实现的方法是将ddl命令放入单引号中,这样,代码在编译是不会识别单引号中的ddl语句,编译器会将引号内的命令当作字符串处理。
–dbms_sql动态解析sql语句(效率低)
create or replace procedure drop_table
(v_table_name in varchar2)
is
dyn_cur number;
dyn_err varchar2(255);
begin
dyn_cur := dbms_sql.open_cursor; -->打开游标
dbms_sql.parse(dyn_cur,‘drop table ‘|| v_table_name||’ purge’,dbms_sql.native);–>解析游标
dbms_sql.close_cursor(dyn_cur); -->关闭游标
exception
when others then
dbms_sql.close_cursor(dyn_cur);
dbms_output.put_line(sqlerrm);
end drop_table;
/
–execute immediate动态解析sql语句,实现在过程中创建表,效率高于dbms_sql包
create or replace procedure proc_test(
table_name in varchar2,
field1 in varchar2,
datatype1 in varchar2
) as str_sql varchar2(200);
begin
str_sql:=‘create table ‘||table_name||’(’||field1||’ ‘||datatype1||’)’;
execute immediate str_sql; --动态执行DDL语句
exception when others then
dbms_output.put_line(‘error:’||sqlerrm);
end;
/
execute proc_test(‘dinya_test’,‘id’,‘number(8) not null’);

一个包由两个分开的部分组成:
  包定义(PACKAGE):包定义部分声明包内数据类型、变量、常量、游标、子程序和异常错误处理等元素,这些元素为包的公有元素。
  包主体(PACKAGE BODY):包主体则是包定义部分的具体实现,它定义了包定义部分所声明的游标和子程序,在包主体中还可以声明包的私有元素。
  包定义和包主体分开编译,并作为两部分分开的对象存放在数据库字典中,详见数据字典user_source, all_source, dba_source.
--创建包emp_pack的package header(子程序的声明部分),声明一个名称为new_emp的过程:
create or replace package emp_pack
is
procedure new_emp
  (  v_ename   scott.emp.ename%TYPE,
     v_deptno  scott.emp.deptno%TYPE  DEFAULT 30);
end emp_pack;
--创建包emp_pack的package body(子程序的代码主体)
create or replace package body emp_pack
is
 function valid_deptno--函数在包的header部分没有声明,这样的函数成为私有函数,因为只有包体可见
    (v_deptno IN scott.dept.deptno%TYPE)
    return boolean
 is
   v_dummy  VARCHAR2(1);
 begin
    select 'x' into v_dummy from scott.dept where  deptno = v_deptno;
    return (true);
    exception
      when others then
        return (false);
 end valid_deptno;--end function
 procedure new_emp --实现存储过程
   (v_ename   scott.emp.ename%TYPE,
     v_deptno  scott.emp.deptno%TYPE  DEFAULT 30)
 is
 begin
   if valid_deptno(v_deptno) then
     dbms_output.put_line('the v_deptno is ok:'||v_deptno||v_ename);
   else
      dbms_output.put_line('the v_deptno is error:'||v_deptno||v_ename);
   end if;
 end new_emp;--end procedure
end emp_pack;
/
重载的概念是指在一个包内部可以拥有同名的子程序,但子程序必须拥有不同的参数变量、参数顺序或参数数据类型。
create or replace package over_load is
function print_it(v_are date) return varchar2;
function print_it(v_are varchar2) return varchar2;
end over_load;
/

create or replace package body over_load is
 function print_it(v_are date) return varchar2--1
 is
 begin
   return to_char(v_are,'yyyy-mm-dd');
 end print_it;
 
 function print_it(v_are varchar2) return varchar2--2
 is
 begin
   return  to_char(v_are,'L99,999.00');
 end print_it;
end over_load;
/
调用:
VARIABLE g_datevalue varchar2(40);
execute :g_datevalue := over_load.PRINT_IT(sysdate); 
print g_datevalue
VARIABLE g_datevalue varchar2(40);
execute :g_datevalue := over_load.PRINT_IT('2017'); 
print g_datevalue
加密:
$ORACLE_HOME/product/11.2.0/dbhome_1/bin/wrap
1.	将包体的代码放在脚本文件xxx.sql中
2.	使用wrap程序处理xxx.sql文件,将生成一个加密版的文件xxx.plb
wrap iname=xxx.sql
3.	使用xxx.plb重新创建包体,这样包体的源代码在数据库中将以处理后的加密版存储
sql>@xxx.plb

触发器

DML触发器
在DML操作前或操作后进行触发,可以在表级触发也可以对每个行操作进行触发。
DDL触发器
在DDL语句操作前或操作后进行触发。

替代触发器
由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。 它就是ORACLE 专门为进行视图操作的一种处理方法。
系统触发器
ORACLE 提供了第四种类型的触发器叫系统触发器。它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等、数据库用户的登录和注销。
触发器触发顺序:
before statement trigger(on table)->before row trigger (on table for each row)->
after row trigger (on table for each row)->after statement trigger (on table)

--实验准备数据(非sys用户)
create table e as select * from scott.emp;
create table d as select * from scott.dept;
 ORA-04089: cannot create triggers on objects owned by SYS

管理
--验证触发器的状态
select trigger_name,status from user_triggers;
--禁用某个触发器
ALTER TRIGGER e_update3 disable;
--禁用某个表上的所有触发器
alter table e disable all triggers;
--删除触发器	
drop trigger e_update3;

DML触发器

--表级触发器:无论修改表中的多少行数据触发器只工作一次
create or replace trigger trigger_d_update
before update on d 
begin
  raise_application_error(-20001,'you update d');
end;
/

发布了52 篇原创文章 · 获赞 2 · 访问量 6374

猜你喜欢

转载自blog.csdn.net/wenwang3000/article/details/99648874