Oracle使用文档

Oracle

基础知识

1.1 数据类型

数据类型描述单位
char(n)定长字符串,默认n为1,max为2000字节字节
varchar2(n)变长字符串,max为4000字节
nchar字符集定长字符串,max为为2000字节字符
nvarchar2字符集变长字符串,max为4000字节
long变长字符串,0-2GB
number(m,n)可变长数值列,m为所有有效数字的位数,n为小数点后的位数,m=[1,38],n=[-84,127]
float存储126位数据,1-126二进制
date7个字节存储日期数据,DD-MON-YY 精确到秒
timestamp存储日期、时间,精确到小数秒,pm、fm

1.2 创建表

create table table_name(
    // 			约束名     约束映射名     	  默认值     判空
	column type constraint constrain_def default default_value NOT NULL,
	...
);
TABLESPACE TBSONE
PCTFREE 20
PCTUSED 40
INSTRANS 10
MAXTRANS 200;

相关参数说明

参数名描述
tablespace指定创建表所在表空间
pctfree 、patused控制数据块空闲空间的方法。两者之和越接近100%,利用率越高,执行update多,pctfree设置可越大,推荐值:pctfree:20%,patused:40%。执行insert、delete越多,且update不会增加记录大小,pctfree设置可越小,推荐值:pctfree:5%,pctused:60%。
initrans、maxtrans控制数据块上的并发事务数量,initrans为初始数量,maxtrans为最大数量。
cache设置表存放数据库高速缓存中的时间
logging日志类型,是否进行日志操作,关闭日志可提高写入效率,导致无法恢复数据
compress相同数据自动压缩,减少占用率,提高查询速度

1.3 修改表结构

alter table <username.> table_name add | modify | drop column column_name

<username.> 为创建表所用的用户

1.3.1 添加字段
alter table sys_user add username varchar2(15);
1.3.2 修改字段
alter table sys_user modify username varchar(20) not null;
1.3.3 删除字段
alter table sys_user drop column username;
1.3.4 设置无用字段列
alter table sys_user set unused (username);  //设置无用字段列
1.3.5 删除所有无用列
alter table sys_user drop unused columns;
1.3.6 修改列名
alter table <username.> tabel_name rename column old_name to new_name;
1.3.7 重命名表
alter table sys_user **rename** **to** new_name;
1.3.8 删除表
drop table table_name;

1.4 约束

1.4.1 数据完整性
名称描述
实体完整性中每一行要求是唯一的实体,不能为空,不能重复
域完整性字段满足特定的数据类型和约束
参照完整性保证关联表数据的正确性
用户定义完整性用户自定义字段约束
1.4.2 约束类型
名称描述
主键约束(PRIMARY KEY)数据表中有且仅有一个,多个列组成的主键成为复合主键,保证数据不重复不为空
外键约束(FOREIGN KEY)使得表与表之间产生联系
唯一约束(UNIQUE)一个表可又多个唯一约束,不能重复
非空约束(NOT NULL)不允许取空值(列级)
检查约束(CHECK)数据筛选作用,保证输入数据的正确性
默认值约束(DEFAULT)指定字段默认值
1.4.2.1 主键约束
alter table table_name add constraint constraint_name primary key (column_name);
1.4.2.2 唯一约束
alter table table_name add constraint  constraint_name unique (column_name);
1.4.2.3 非空约束
alter table table_name add constraint constraint_name modify (column_name )not null;
1.4.2.4 检查约束
alter table table_name add constraint constraint_name check (condition);

condition 检查条件 (grade>0 and grade <100)

1.4.2.5 外键约束
alter table table_name1 add constraint constraint_name foreign key (column_name)
reference table_name2 (column_name) on delete cascade;

reference 引用(关系)

on delete cascade 级联删除

1.4.2.6 删除约束
alter table table_name drop constraint constraint_name;

1.5 表数据操作

1.5.1 插入数据
insert into table_name (column_name1,column_name2,column_name3,column_namen)
values (value1,vaule2,value3,valuen)
1.5.2 更行数据
update table_name set column_name1 = value1,column_name2 = value2 where search_condition; 
1.5.3 删除数据
delete from table_name where search_condition;

1.6 查询

1.6.1 简单查询
select
distinct     //去重 
	*
from table_name 
where search_condition 	//筛选条件
group by group_condition //排序条件
having having_condition    //进一步筛选条件
order by order_condition asc|desc(|降序); //升降序排列
1.6.2 模糊查询
select * from table_name like '李%'

若条件中有特殊字符,需加上 ‘/’ 转义

1.6.3 控制判断查询
select * from table_name where column IS NULL | IS NOT NULL
1.6.4 结果统计查询
select
	id,count(username),avg(score) 
from table_name 
where search_condition 
group by roolup(column_name);

ROOLUP 用来对数据进行进一步的统计(求和、平均数、最大值。。。)

1.6.5 连接查询
1.6.5.1 交叉查询
select column_name from table_name1 cross join table_name2;
1.6.5.2 内连接(简单连接)

只能查询出两个或多个表连接时匹配的记录(多表联查显示符合筛选条件的数据)

1.6.5.2.1 等值连接
select * from table_name1 a inner join table_name2 b on a.id = b.id

筛选条件为等值条件

1.6.5.2.2 非等职连接

筛选条件为非等值条件

1.6.5.2.3 自连接

多个查询表为同一个表

1.6.5.3 外连接
select * from table_name1 a left | right | full outer join table_name2 b on a.id = b.id

联合查询出两个表中的所有数据,数据不匹配时主表显示数据,副表显示数据为空。

1.6.5.3.1 左外连接

联合查询时,左表数据全显示,右表仅显示匹配数据

1.6.5.3.2 右外连接

联合查询时,左表数据仅显示匹配数据,右表数据全显示

1.6.5.3.3 完全外连接

无论数据是否匹配,所有表中数据全显示

1.6.5.3.4 左、右连接特殊方式
select * from table_name1 a,table_name2 b where a.id = b.id(+);

(*) 在哪个表后面有 星号 ,则将该表设为主表

1.6.5 子查询
1.6.5.1 in 子查询
select * from table_name where id [NOT] in (子查询)

in 用来获取一个集合(子查询返回结果)

not in 取非

1.6.5.2 比较运算符子查询
select * from table_name wherer id = (子查询)

’ = ’ ‘<’ ‘>’ ‘<=’ '>= ’ ‘!=’ 只能用来获取单值,多值会发生错误

1.6.5.3 Any 、All 子查询
名称描述
ANY满足子查询结果的任何一个(极值)
SOME与Any含义相同
ALL满足子查询结果的所有结果(所有值)

用来解决运算符子查询只能用于获取单值问题。

1.6.5.4 Exists子查询
select * from table_name where exists(子查询) and name != 'xiaoye'

Exist用于判断是否存在条件数据,子查询返回的结果为逻辑值,查询结果为空,则exists(子查询)就返回true,否则,返回false,从而子查询中给出列名无实际意义。

1.6.6 集合操作
操作符说明
UNION[ALL]返回各个查询检索出的所有行,有All则包括重复值,没All则不包括
INTERSECT返回两个查询检索出的共有行
MINUS返回第一个查询的结果减去第二个查询的结果的剩余行数据
select * from table_name1 where search_condition1
union 
select * from table_name2 where search_condition2;
1.6.7 sql plus
1.6.7.1 sql plus命令
命令说明
A[ppend] text追加文本,将text附加到当前行之后
C[hange] / old text /new text替换文本,将当前行中的old text 替换成new text
CL[ear] BUFF[ER]清除文本,清除缓冲区中的所有行
DEL n删除命令,删除第n行,省略n表示删除当前行(行号从1开始)
L[IST] N列出第n行sql语句,省略n时,表示列出缓冲区中所有行
R[UN] 或 /运行缓冲区中保存的语句。也可以用 / 来运行缓冲区中保存的语句
n将第n行作为当前行

**[]**中为省略部分,实际操作时省略即可

1.6.7.2 追加语句
select * from table_name ;
append where search_condition;
1.6.7.3 替换语句
change /name like '李%'  /name like '王%'
1.6.7.4 保存、检索并运行文件
命令说明
SAV[E] file_name [{REPLACE|APPEND}]将sql*plus缓冲区的内容保存到由file_name指定的文件中。APPEND是将缓冲区中内容追加到现有文件之后;REPLACE是直接覆盖现有文件。注意:file_name可以只写一个文件名,也可以写一个具体保存路径,如果只写一个文件名,就表示把当前缓冲区的内容保存到默认文件夹中。
GET file_name将file_name指定文件的内容读入Sql*plus
STA[RT] file_name将file_name指定文件内容读入sql*plus并运行,扩展名可写成.sql
@file_name与start命令相同
ED[IT]将缓冲区内容复制到afiedt.buf的文件中,然后启动操作系统中默认编译器,在推出编译器是,编辑的文件将会被复制到缓冲区中
ED[IT] file_name与edit命令相同,但可以指定编辑的文件,文件名可以使用file_name 参数指定
SPO[OL] file_name将sql*plus中的输出结果复制到file_name指定的文件中,扩展名可写成.sql
SPO[OL] OFF停止将sql*plus中的输出结果复制到file_name指定的文件中,并关闭该文件,执行语句后,才把查询结果写入到指定文件中。

具体命令操作如下

select * from table_name where search_condiion
// 保存缓冲区内容至demo.sql中
save demo.sql

// 获取缓冲区内容
get demo.sql

// 加载并运行demo.sql
start demo.sql

// 编辑缓冲区 输入命令后windows会默认打开记事本并展示缓冲区中的内容
edit 

// 将sql*plus的输出结果复制到out.tex中
sql> spool out.txt
sql> /
sql> spool off

// 若想将输出结果文件保存到其他位置(加上绝对路径即可)
spool e:\out.txt
1.6.7.5 格式化输出列
1.6.7.5.1 用法
COL[UMN]{ column_name | alias }[options]

column_name 指定列名

alias 指定要格式化的列别名

options 指定用于格式化列或别名的一个或多个选项

1.6.7.5.2 格式化选项
选项说明
FORP[MAT] format将列或别名的显示格式设置为由format字符串指定的格式
HEA[DING] heading将列或别名的变体中的文本设置为由heading字符串指定的格式
JUS[TIFY] [{LEFT | CNETER | RIGHT}]将列输出设置为左对齐、居中、右对齐
WAR[PPED]在输出结果中将一个字符串的末尾换行显示。该选项可能导致单个单词跨越多行
WOR[D_WRAPPED]与WRAPPED选项类似,不同之处在于单个单词不会跨越两行
CLE[AR]清除列的任何格式化(将格式设置回默认值)
1.6.7.5.3 示例

1、设置输出格式

column student_id format all  --直接对列格式化输出
column sname format A6		 
column ssex format A4
column 出生日期 foramat A11   --对列别名进行格式化输出
column nationality format A11
column dept_id heading 系部代码 format A8  --指定列标题并格式化输出

2、输出语句

select student_id,sname,ssex,to_char(sbirth,'yyyy-mm') as 出生日期,nationality,dept_id
from students
where sname like '王%'
1.6.7.6 设置页面大小和行大小
set PAGESIZE m  // 设置行数

set NEWPAGE n  // 设置页间隔

set LINESIZE h // 设置行字符数

show PAGESIZE  // 显示行数

show NEWPAGE  // 显示页间隔数

show LINESIZE // 显示行字符数

m 每页显示的行数 默认值24

n 每页之间间隔的空格数

h 每行展示的字符数 默认值80

set pagesize 100
cloumn course_id format A10 
select * from students left outer join sc
on students.student_id = sc.student_id;
1.6.7.7 清除格式
column dep_id clear  // 清除列格式
clear columns      // 清除所有列格式

PL/SQL

1 基础知识

1.1 简介

  • 一种应用在数据库中的程序设计语言。

  • 可以定义常量、变量、赋值语句、表达式、分支、循环

  • 可以在程序中嵌入sql语句

  • 数据操作和查询语句定义在程序块中

  • 是面向过程语言和sql语言的结合,在sql中扩充了面向过程的程序结构

  • 块是程序中最基本的结构

1.2 结构体

命令名称描述
[DECLEAR]声明部分声明 pl/sql 用到的常量、变量、类型、游标、用户定义异常
BEGIN执行部分sql语句、pl/sql语句构成的程序
[EXCEPTION]异常部门当程序出现异常时,捕捉异常并处理
END标记程序体结束

1.3 程序块

declare
	c_name varchar2(20);
begin 
	select cname info c_name
	from courses
	where course_id = '0019';
	dbms_output.put_line('代码是0019的课程名称是:'||c_name);
exception
	where no_data_found then
	dbms_output_put_line('没有这门课程!');
	where too_many_rows then
	dbms_output.putline('有多门课程的代码重复,均为0019')
end;

2 基本语法

2.1 常量、变量

2.1.1 常量的定义
column_name constant datatype : = value;

id constant integer : = 100; 
2.1.2 变量的定义
column_name datatype (宽度) : = <初始值>;

address varchar2(50);

变量定义时需要进行初始化,若未初始化,则会被赋值为NULL

2.2 表达式、运算符

2.2.1 表达式
  • 由运算符串起来的一组数
  • 表达式数值由组成它的变量、文字的取值和运算符决定
  • 运算符的优先级决定了表达式求值的顺序
2.2.2 运算符
运算符意义
+、-正负
+加法
-减法
*乘法
/除法
**

优先级 幂 > 正负 > 乘除 > 加减

2.2.2.1 关系运算符
运算符意义
<>不等于
!=不等于
^=不等于
<小于
>大于
=等于
2.2.2.2 逻辑运算符
运算符意义
NOT逻辑非
AND逻辑与
OR逻辑或
2.2.2.3 其他符号
运算符意义样例
/ /多行注释/* this is a comment*/
单行注释– this is a comment
||并置(+)full_name : = ‘this is a’ || ‘’|| ‘name’
: =赋值id : = id +1
字符串界定符(字符串包裹)if vall = ’sandra‘
.项分隔select * from student.table_name;
;语句结束符select * from student.table_name;
()列表分割(‘tom’,‘mary’,‘sam’)

2.3 条件语句

2.3.1 if 语句
declare 
	score number;
begin 
	select grade into score
	from sc
	where course_id = '0001' and student_id ='2330170424';
	dbms_output.put_line('课程0001号成绩是:'|| score);
	if score >= 90 then
		dbms_output.put_line('成绩优秀~');
	elseif score >= 80 then
		dbms_output.put_line('成绩良好~');
	elseif score >= 70 then
    	dbmn_output.put_line('成绩一般~');
   elseif score >= 60 then
   		dbms_output.put_line('及格~');
   else 
   		dbms_output.putline('不及格');
   end if
end;
2.3.2 case 语句
declare 
	score number;
begin 
	select grade into score
	from sc
	where course_id = '0001' and student_id ='2330170424';
	dbms_output.put_line('课程0001号成绩是:'|| score);
	case
       when score >= 90 then
          dbms_output.put_line('成绩优秀~');
       when score >= 80 then
          dbms_output.put_line('成绩良好~');
       when score >= 70 then
          dbmn_output.put_line('成绩一般~');
       when score >= 60 then
          dbms_output.put_line('及格~');
       else 
          dbms_output.putline('不及格');
   end case;
   dbms_output.putline('搜索case结构验证完成!');
end;

2.4 循环语句

2.4.1 简单循环
declare
	i integer :=1;
begin
	loop
		insert into temp values(i)exit when  i = 5;
		i := i+1;
	end loop;
	commit;
end;
2.4.2 for 循环
begin
	for v_counter in 1 ... 10 loop
		insert into temp values(v_counter);
	end loop;
	commit;
end;

for v_conter in reverse 1…10 loop

reverse => 10…1

2.4.3 while 循环
delcare
	i int := 1;
begin
	when i<10 loop
		insert into temp values(1);
		i := i+1;
	end loop;
	commit;
end;
2.4.4 嵌套循环
declare
	i integer;
	j integer;
begin
	<<outer>>
	for i in 1...5 loop
		dbms_output.put_line('外层循环:i的值是:' || i);
		<<inner>>
		for j in 1...5 loop
			dbms_output.put_line('内层循环:j的值是:'||j);
			if j = 3 then
             exit outer;
          end if;
		end loop inner;
	end loop outer;
	dbms_output.put_line('嵌套循环语句块结束~')
end;

outer 和 inner 标签,循环体外层标记

2.5 常用函数

2.5.1 数值型函数
函数用途
ABS(-8)取绝对值
CEIL(116.24)向下取整
FLOOR(116.24)向上取整
POWER(15,4)幂函数(次方)
ROUND(123.456,2) = 123.46四舍五入(小数点后)
2.5.2 字符型函数
函数用途
ASCLL(‘a’)将字母转换成ASCLL码值
CHR(‘97’)将ASCLL值转换成字母
LENGTH(‘hello’)字符串长度
UPPER(‘hello’)将字符串转换成大写形式
LOWER(‘HELLO’)将字符串转换成小写形式
REPLACE(‘计算机专业考试’,‘专业’,‘等级’)替换字符串
RPAD(‘计算机’,15,‘等级考试’)右加操作,中间数字为字符串总长度 (’+’)
LPAD(‘计算机’,15,‘等级考试’)左加操作,中间数字为字符串总长度(’+’)
TRIM(’ oracle database 12c ')去掉字符串前后空格
LTRIM(’ oracle database 12c’)去掉字符串前前空格
RTRIM('oracle database 12c ')去掉字符串后空格
2.5.3 日期型函数
函数用途
SYSDATE()系统当前日期和时间 (‘11-06月 -21’)
SYSTIMESTAMP()系统时间(时区、精确到微秒)(‘11-06月 -21 18.46.00.00001’ 下午 + 08:00)
LAST_DAY(date)指定日期,对应月份最后一天对应日期
NEXT_DAY(date,char)指定日期,下个星期’’对应日期,char指定星期全称、缩写都可
MONTHS_BETWEEN(date1,date2)指定日期间,月的个数
EXTRACT()指定日期,提取年、月、日、时、分、秒

EXTRACT(YEAR FROM SYSDATE);

EXTRACT(YEAR FROM TIMESTAMP ‘2021-6-11 18:46:00’);

2.5.4 统计函数
函数用途
COUNT(column_name)记录某列数据的数量
MAX(column_name)最大值
MIN(column_name)最小值
SUM((column_name)求和值
AVG(column_name)平均值
2.5.5 转换函数
函数
TO_CHAR()函数转换成数值、日期转换成字符串
TO_DATE()字符串转换成日期
CAST数字转字符、字符转数字、字符转日期、日期转字符

2.6 游标

2.6.1 基本原理
  • 为了协调pl/sql为变量只能存放一条记录和查询结果记录数不确定的,且不知道要声明变量的个数而设立。
  • 是指向内存区域(工作区)的指针
  • 是一种结构化数据类型为应用程序提供对具有多行数据查询结果集中的每一行数据分别进行处理的方法。
2.6.2 显式游标

​ **用途:**暂存查询取出的多行数据,然后一条一条的进行处理。

2.6.2.1、声明游标

将游标与一个select语句进行关联,语句对应记录结果集返回给游标

cursor cursor_name is select_statement;

**注意:**select_statemen : select 语句

2.6.2.2、打开游标

执行游标定义的查询语句,并将数据暂存在游标区域中,游标指针指向游标中第一条记录。

open cursor_name;

打开游标后:

  • 检查联编变量的取值
  • 根据联编变量的取值,确定活动集
  • 活动集的指针指向第一行
2.6.2.3、提取游标
fetch cursor_name into value1,value2,...;
fetch cursor_name into pl/sql 记录

cursor_name为声明且打开的游标

into 后 变量数量应与游标中字段相匹配,且一一对应。

2.6.2.4、关闭游标
close cursor_name

所有记录处理完后需关闭游标,关闭后释放游标区域,占用内存空间回收,后续无法再提取数据。

2.6.2.5、代码示例
declare 
	id varchar2(12);  -- 声明变量存储游标中的学生编号
	name varchar2(20) -- 声明变量存储游标中的学生姓名
	-- 定义游标 sid 参数名 指定用户编号
	cursor cur(sid number) is
		select student_id,sname
		from students 
		where student_id = sid;
begin 
	open cur('001'); -- 打开游标,读取编号为001的学生信息
	fetch cur into id,name; -- 读取当前有标位置的记录
	close cur; -- 关闭游标
	dbms_output.put_line('学生学号:'||id|| ',学生姓名:' || 'name');  -- 打印获取记录
end;
2.6.3 隐式游标
  • 非pl/sql程序中定义
  • 一般来说,执行所有sql语句时,Oracle系统自动分配的游标(实则仅限于update、delete)
  • 不需要打开、关闭操作(全自动)
2.6.4 游标属性
  • %isopen、%found、%notfound、%rowcount四种属性
  • 描述与游标相关操作的dml语句执行情况
  • 只能用于pl/sql流程控制语句中,不能用于sql语句中
属性名用途
%isopen判断游标是否处于打开状态,若未打开,需打开游标再向下操作
%found判断当前游标是否指向有效行
%notfound判断当前游标是否指向无效行
%rowcount记录游标提取记录的行数,当前游标所在行号
2.6.5 游标变量
  • 动态变量
  • 存放多行记录的结果集
  • 不用于特定的查询绑定,再打开游标后才能确定所对应的查询。
  • 可以依次对应多个查询
2.6.5.1 游标变量的声明
ref type  -- ref : 变量名 type :  已定义类型
TYPE<类型名> is ref cursor  -- <类型名> 新的引用类型名
return <返回类型>;       -- <返回类型> 记录类型,指名最终由游标变量返回的选择列表类型

游标变量返回类型必须是一个记录类型。可以被用户显示声明,也可以通过%rowtype隐式声明。

2.6.5.2 游标变量的打开
  • 如果要将游标变量和特定select语句相关联,需使用open for 语句
  • 如果游标受限,select语句的返回类型必须与游标所限的记录类型相匹配,不匹配会报 ORA_6504
open <游标变量> for <select 语句>
2.6.5.3 游标变量的关闭
  • 对已经关闭的游标变量再次关闭时是非法的。
2.6.6 代码示例
declare 
	rec_dept dept%rowtype;  -- 声明变量存储游标中的学生
	-- 定义游标 sid 参数名 指定用户编号
	cursor cur is
		select *
		from dept
begin 
	if cur%isopen = false then
		open cur; -- 打开游标
	end if;
	fetch cur into rec_dept; -- 读取当前有标位置的记录
	while cur%found
	loop
		dbms_output.put_line('系统部编号:'|| rec_dept.dep_id || ',系部名称:' || 'rec_dept.dept_name' || ',系主任:' || ',rec_dept.director'); -- 打印读取数据
		if cur%rowcount = 4 then -- 只读取4条数据
			exitend if;
		fetch cur into rec_dept; -- 读取当前游标位置数据
		exit when cur%notfound;
	end loop;
	close cur; -- 关闭游标
end;
2.6.7 游标for循环
  • 显示游标快捷使用方式
  • 不需要手动open、fetch、close
2.6.7.1 常规循环
declare
	-- 声明游标
	cursor cur is
		select * 
		from dept;
begin
	-- for循环提取游标数据
	for rec_dep in cur loop
		dbms_output.put_line('系统部编号:'|| rec_dept.dep_id || ',系部名称:' || 'rec_dept.dept_name' || ',系主任:' || ',rec_dept.director'); -- 打印读取数据
	end loop;
end;
2.6.7.2 简易写法
begin
	-- for循环提取游标数据
	for rec_dep in (select * from dept) loop
		dbms_output.put_line('系统部编号:'|| rec_dept.dep_id || ',系部名称:' || 'rec_dept.dept_name' || ',系主任:' || ',rec_dept.director'); -- 打印读取数据
	end loop;
end;
2.6.8 游标的更新(for update)
  • 对游标中数据需要进行修改和删除时,使用for update以便于打开游标时锁定游标结果集在数据库表中对应的数据行
  • 游标可带参,也可不带参
  • 游标打开后为其加锁,关闭后释放锁,保证用户数据访问的正确性和一致性
declare
	rec_dept dept%rowtype;
	cursor cur is
		select * from dept
		for update;
begin
	open cur;
	loop
		exit when cur%notfound;
		fetch cur into rec_dept;
		if rec_dept.dept_id = '001' then  -- 更新表
			update dept 
			set director = '测试数据'
			where current of cur;  -- 修改游标当前行
		end if;
	end loop;
	commit;
	close cur;
end;

2.7 异常处理

名称描述
预定义异常Oracle标准错误,无需用户自定义程序解决,用于用户查找代码错误
非预定义异常其他标准的Oracle错误,需用户自定义程序解决
自定义异常程序员自定义异常,特定条件下抛出异常
declare
	v_sid integer :='&学生学号'; -- 声明变量,其值由替换变量'&学生学号'决定
	v_cid integer :='&课程号';
	v_grade integer;
	-- 自定义异常
	Student_Grade Exception;
begin
	select grade into v_grade 
	from students
	where sid = v_sid and course_id = v_cid;
	if v_grade <= 0 then
		raise Student_Grade;
	end if;
	dbms_ouput.put_line('学号为:'||v_sid ||'的同学选修的'||v_cid||'号课程的成绩为:'||v_grade');
   -- 异常处理部分
   exception
      when Student_Grade then
         dbms_output.put_line('课程成绩为0或不存在~');
         rollback;
      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;

3 存储过程、函数、触发器、程序包

3.1 存储过程

3.1.1 用途
  • 用于Oracle开发者数据转换或查询报表
  • 用于执行某些特定的操作或任务,将经常需要执行的特定操作写成过程
  • 通过过程名可以多次调用过程,实现程序的模块化设计,节省用户时间,提高程序效率
3.1.2 描述
  • 在数据库中定义子程序,将固定操作集中起来放在子程序中,然后统一交给Oracle数据服务器完成,以完成某特定的功能,这种子程序称之为存储过程。
  • 存储在数据库服务器中的封装了一段或多段sql语句的pl/sql代码块。
3.1.3 好处
  • 存储过程在服务器端运行,执行速度快
  • 存储过程执行一次后驻留在Oracle数据库服务器的高速缓存中,方便二次调用,提高系统性能
  • 保证了数据库的安全,在禁止用户直接访问应用程序中的某些数据表的情况下,授权执行访问这些数据表的存储过程
  • 自动完成需要预先执行的任务,可以设置为系统启动时自动执行,方便用户使用。
3.1.4 创建和执行存储过程

1、创建存储过程(示例请看执行存储过程

create or replace procedure procedure_name
{
	parameter_name1  in | out | inout date_type1,
	parameter_name2  in | out | inout date_type2,
}
is | as
	parameter_name3 datatype  //申明部分
begin
	执行部分
exception
	异常处理部分
end procedure_name;

or replace : 表示制定过程已存在,则覆盖同名存储过程

procedure_name : 存储过程名称

parameter_name1: 存储过程参数(接收外界传参)

in : 向存储过程传递参数

out : 从存储过程返回参数

data_type : 传入参数类型,可带默认值

as | is : 在之后声明的变量主要用于过程体内,不能加declare

2、执行存储过程

存储过程创建后,通过授权后,存储过程即可被调用执行。

-- 创建存储过程
create or replace procedure insert_student is
begin
	insert into students
	values('001','liushun','男',to_date('1999-10-21','yyyy-MM-dd'),'汉族','0101','010101');
	exception
		when dup_val_on_index then
			dbms_output.put_line('重复学生Id');
		when others then
			dbms_output.put+line('未知错误~');
end insert_student;

-- 执行存储过程
set serveroutput on -- 保证了dbms_output.put_line成功输出~
begin
	inser_student;
end;

3、查看存储过程

存储过程一旦创建就会存储到数据库服务器上,orcale通过使用试图user_source查看已存在的存储过程。

select * from user_source where name = 'insert_student' order by line

user_procedures视图部分列

类型说明
object_namevarchar2(30)对象名,可以是过程、函数、包名
procedure_namevarchar2(30)过程名
aggregatevarhcar2(3)过程是否是聚合函数,Yes、No
impltypeownervarchar2(30)实现类型的所有者名称(如果有)
impltypenamevarchar2(30)实现类型名(如果有)
parallelvarchar2(3)过程是否支持并行查询,Yes、No
3.1.5 带参数的存储过程
  • 允许带参数,增加存储过程灵活性
  • 如果存储过程使用了存储,执行存储过程时必须为其指定参数
3.1.5.1 IN 参数(默认)

参数由调入者传入,只能够被存储过程读取

-- 创建存储过程
create or replace procedure insert_student(
     p_id in varchar2,
     p_name in varchar2,
     p_sex in varchar2,
     p_birthday in date,
     p_nat in varchar2,
     p_did in varchar2,
     p_cid in varhcar2
 )
 is 
 begin
 	insert into students
 	values(p_id,p_name,p_sex,p_birthday,p_nat,p_did,p_cid);
 	exception 
 		whene dup_val_on index then dbms_output.put_line('重复学生id');
 		when others then dbms_output.put_line('未知错误~');
 end insert_student;
 
 -- 执行过程方式1 名称传递
 execute insert_student(
     p_id => '001',
     p_name => 'liushun',
     p_Sex => '男',
     p_birthday => to_date('1999-10-21','yyyy-MM-dd'),
     p_nat => '汉族',
     p_did => '0101',
     p_cid => '010101'
 );
 
-- 执行过程方式2 位置传递
execute insert_student('001','liushun','男',to_date('1999-10-21','yyyy-MM-dd'),'汉族','0101','010101');

-- 执行过程方式3 组合传递
execcute insert_student('001','liushun','男',to_date('1999-10-21','yyyy-MM-dd'),o_nat => '汉族',p_did =>'0101',p_cid => '010101');
3.1.5.2 OUT 参数

参数由存储过程写入

-- 创建存储过程 (获取输入学生姓名对应的所有学科名称)
create or replace procedure p_coursename(p_sname in varchar2,coursename out varchar2)
is
v_coursename varchar2(50);
begin
	for student in (
    	select c.cname from students s,sc,courses c
    	where s.student_id = sc.student_id
       and sc.courese_id = c.course_id
       and s.name = p_sname
	) loop
	v_coursename := v_coursename || student.cname;
	end loop;
	coursename := v_coursename;
end p_coursename;

-- 创建执行过程
variabel c_name varchar2(20)
exec p_coursename('刘顺',:c_name);
print c_name;
3.1.5.3 INOUT 参数

​ 同时具有in和out参数特性,过程中可以读取和写入参数

-- 创建存储过程 (交换值)
create or replace procedure p_swap(p_v1 in out number,p_v2 in out number)
is
	v_temp number;
begin 
	v_temp := p_v2;
	p_v1 := p_v2;
	p_v2 := v_temp;
end p_swap;

-- 执行存储过程
declare 
	var_1 number := 10;
	var_2 number := 20;
begin 	
	p_swap(var_!,var_2);
	dbms_output.put_line('var_1=' || var_1);
	dbms_output.put_line('var_2=' || var_2);
end;
3.1.5.4 默认值

​ 创建存储过程同时给输入参数提供默认值,out、inout参数不具有默认值

-- 创建存储过程
set serveroutput on 
create or replace proceduce sum_course_credit(
    stu_id in varchar2 defalut '2330170424'
)
as
sum_credit number;
begin
	select sum(credits) into sum_credit from courses
	where course_id in (select course_id from sc where student_id = stud_id);
	dbms_ouput.put_line(sum_credit);
end sum_course_credit;

-- 执行存储过程
begin 
	sum_course_credit('2330170424');
	sum_course_credit();
end;
3.1.6 为过程添加局部变量和子过程

过程可以定义局部变量和子过程,局部变量可以在本过程内的任何地方使用,子过程只能被其父过程调用。

-- 修改教师表,添加工资列
alter table teacher
add t_sal number default 2000;
-- 创建存储过程
create or replace proceduce insert_teacher(
	id in varchar2,
	name in varchar2,
	sex in varchar2 default '男',
 	birthday in date,
	eduction in varchar2 default '研究生',
	profess in varchar2 default '讲师',
	dept_id in varchar2,
	sal in number default '2000'
) is
	tsal in teacher.sal%type;
procedure check_sal(salary in out number) is
	begin 
		if salary<2000 then salary:=2000;
	end if;
end check_sal;

begin 
	tsal := sal;
	check_sak(tsal);
	insert into teacher(teacher_id,t_name,t_sex,t_birthday,t_education,t_profess,t_dept_id,t_sal)
	values(id,name,sex,birthday,eduction,profess,dept_id,sal);
end insert_teacher;
-- 执行过程
begin
	insert_teache('001','liushun',to_date('1999-10-21','yyyy-MM-dd'),'0101','010101');
end;

1、传入sal = 1500,子过程调用check_sal,最终sal = 2000

2、需先定义局部变量,后定义子过程

3、%type变量声明:查看数据库列的数据类型,将数据库类型用于所声明对的变量

​ 好处:

​ 1、用户无需检查数据类就可确保定义的变量能够存储检索的数据

​ 2、后续对数据库结构进行修改,用户不需要考虑对变量进行二次修改,

​ 缺点:

​ 系统每次都需v要查看数据字典来确定变量数据类型,降低了程序的性能

3.1.7 修改和删除存储过程
3.1.7.1 修改
通过 or replace 关键字即可完成过程的修改,覆盖原有定义
3.1.7.2 删除
drop proceduce procedure_name;

3.2 函数

3.2.1 创建函数
  • 函数由return 数据类型自居,用于指定函数返回值的数据类型
  • 在函数体内,用户可以在任何地方使用return,返回值类型必须和函数头中声明的类型保持一致
create or replace function function_name(
    parameter1 in | out | in out data_type1,
    parameter2 in | out | in out data_type2,
 	...
)
return data_type;
is | as
	...声明部分
begin
	...执行部分
exception
	...异常处理部分
end function_name;
3.2.2 调用函数

调用函数和调用过程不同,调用函数需要定义一个变量来保存返回的值

declare
	sum number := 0;
begin
 	sum := function_name(parameter1);
 	dbms_output.put_line(sum);
end;
3.2.3 删除函数
drop function <function_name>;
3.2.4 示例
-- 创建函数
create or replace function count_stu(f_cname in varchar2)
return number;
as
result number := 1;
begin
	select count(distinct student_id) into result
	from sc,courses c
	where course_id = c.course_id
	and c.cname = f_cname;
	return(result);
end count_stu;

-- 执行函数
declare 
	sum number := 0;
begin
	sum := count_stu('高数');
	dbms_output.put_line(sum);
end;

3.3 触发器

3.3.1 概述
3.3.1.1 作用
  • 安全性: 触发器可以基于数据库的值使用户具有操作数据库的某种权利
  • 审计:触发器可以跟踪用户对数据库的操作
  • 实现复杂的数据完整性规则
  • 同步实时的复制表中数据
  • 自动计算数据值,数据值达到一定要求后进行特定的处理
3.3.1.2 分类
名称描述
DML触发器对表或视图执行DML操作时触发
INSTEASD OF 触发器只定义在试图上用来替换实际的操作语句
系统触发器在对数据库系统进行操作时触发(DDL、启动或关闭数据库)
3.3.1.3 概念
要素条件
事件DML、DDL、数据库系统事件(系统启动、退出)、用户事件(登录或退出数据库)
条件where指定的逻辑表达式,为true时触发事件、执行触发器
对象表、视图、模式、数据库
操作要执行的pl/sql程序(执行部分)
时机before(防止错误发生或实现业务规则)、after(记录操作或事后处理)
子类型row(行触发,受触发器影响每一行)statement(语句触发,受触发器影响的一行)

注意:

​ 1、触发器应建立在哪个表之上

​ 2、触发器应该对什么样的DML操作进行响应

​ 3、指定DML操作之后还是之前触发

​ 4、对每次DML响应一次,还是受DML影响的每一行数据都响应一次

3.3.1.4 触发器执行顺序
  • Before触发器
  • 执行语句
  • After触发器
  • 多个Before/After 触发器,先创建先执行
3.3.1.5 创建触发器语法
create or replace trigger trigger_name
before | after | instead of
insert or delete or update of column_name ...
on table_name | view_name
for each row when trigger_condition -- 或省略,默认语句触发,这里表示行触发
begin
	trigger_body
end trigger_name;

trigger_name : 触发器名称

instead of : 创建替代触发器,触发事件不执行,执行触发器本身操作

insert or delete or update : 多个触发事件之间使用or连接

of column_name: 指出在哪一列触发

on table_name : 指定表创建触发器

3.3.2 DML触发器
3.3.2.1 语句级触发器
-- 创建语句级触发器的测试表
create table syslog(
	who varchar2(20),
	when date
);
-- 创建语句级触发器
create or replace trigger user_ls.delteUser
	after delete on user_ls.user
begin
	insert into user_ls.syslog values(user,sysdate);
end deleteUser;
-- 测试触发器
	delete user_ls .user where id = 1;
3.3.2.2 行级触发器
-- 创建行触发器
create or replace del_stu
	after delete on user_ls.students
	for each row when (old.dept_id= '001');
begin
	dbms_output.put_line('1行数据已被成功删除~');
end del_stu;
-- 测试触发器
delete from user_ls.students where dept_id = '001';
3.3.3 替代触发器
  • 用来对另一个表或视图进行DML操作
  • 定义替代触发器后,表或视图的操作不再被执行,而去执行触发器主体中的操作
  • 通过在替代触发器中编写代码以实现对组成视图的各个表进行操作
-- 创建视图
create or replace trigger user_ls.update_dep_view
	instead of update on user_ls.dep_view
	for each now
begin
	-- 更新teacher表
	update user_ls.teacher
	set tname =: new.tname
	where teacher_id := old.teacher_id;
   -- 更新dept表
   update user_l.dept 
   set dept_name =: new.dept_name
   where dept_name =: old .dept_name;
end update_dep_view;

instead of 没有before和after关键字,等同于after的行级触发器,用户不能修改其中的:new值

3.3.4 系统事件触发器
  • 数据库的启动(startup)
  • 数据库的关闭(shutdown)
  • 数据库服务器出错(servererror)
-- 创建系统时间触发器测试表
create table db_log (op_date timestamp);

-- 创建系统事件触发器
create or replace trigger db_startup
	after startup
	on startup
	on database
begin 
	insert into db_logvalues(sysdate);
end db_startup;

db_startup触发器作用: 在用户登录数据库时,记录登录时间

startup 和 servererror 只可以创建ater startup触发器

shutdown 只能创建before shutdown 触发器

servererror触发器既能够与数据库相关联,又能够与特定模式相关联,与特定模式相关联时,表示只有该模式上的操作所导致的错误才会触发。

3.3.5 用户事件触发器
  • 与数据库定义语句DDl 或用户的登录/注销等事件相关的触发器
  • 包括以下语句:
    • create
    • alter
    • drop
    • analyze
    • associate statistics
    • disassociate statistics
    • audit
    • notaudit
    • commit
    • grant
    • revoke
    • rename
    • truncate 以上触发事件都可为after、before
    • logoff 只能为before
    • suspend 只能为after
    • logon 只能为after
-- 创建用户存储信息的表
create table user_ls.drop_obj(
	object_name varchar2(20),
	object_type varchar2(20),
 	drooped_date date
);
-- 创建用户事件触发器(在用户删除对象之前记录到日志信息表)
create or replace trigger user_ls.dropped_obj
	before drop
	on user_ls.schema
begin
	insert into user_ls.drop_obj
	values(dict_obj_name,dict_obj_type,sysdate);
end dropped_obj;
3.3.6 管理触发器
3.3.6.1 查看触发器

与触发器有关的数据字典

数据字典描述
USER_TRIGGERS存储当前用户所拥有的触发器
DBA_TRIGGERS存储管理员所拥有的触发器
ALL_TRIGGERS存储所有触发器
USER_OBJECTS存储当前用户所拥有的对象,包括触发器
DBA_OBJECTS存储管理员所拥有的对象,包括触发器
ALL_OBJECTS存储数据库中所有对象,包括触发器

​ USER_TRIGGERS表主要列的意义

列名描述
TRIGGER_NAME触发名
TRIGGER_TYPE触发时间After、Before,行级触发、语句出发
TRIGGERING_EVENT触发器事件
TABLE_NAME与触发器相关的表或视图
BASE_OBJECT_TYPE与触发器相关的对象类型:表、视图、模式、数据库
WHEN_CLAUSE触发器的when子句代码
STATUS触发器状态:启用、禁用
DESCRIPTION类型或事件信息的概述
TRIGGER_BODY触发器中的pl块
3.3.6.2 启动和禁用触发器(挂起)
alter trigger trigger_name disable | enable
3.3.6.3 修改触发器
create or replace ...
3.3.6.4 删除触发器
drop trigger trigger_name

3.4 程序包(Class)

  • 用于将逻辑相关的PL/SQL块或元素(变量、常量、自定义数据类型、异常、过程、函数、游标)组织在一起,作为一个完整的单元存储在数据库中
  • 使用包组织过程、函数、游标后,使得程序设计实现模块化
  • 调用包后会将其放在内存中,方便二次调用从内存中直接读取,提高程序运行效率
  • 两部分组成
    • 规范(specification):
      • 说明部分(包头、头部)
        • 过程名
        • 函数名
        • 其他对象名及参数
    • 包体(body):
      • 执行部分(须和规范中声明的完全匹配)
        • 过程
        • 函数
        • 参数返回值

包体中未在规范中列出的部分属于私有对象(private),只能用在包体内(对用户隐藏复杂性)

3.4.1 包规范的创建
create or replace package package_name
is | as
package_specifiction
end package_name

package_specification : 用于列出公共过程、函数、类型和对象

3.4.2 包体的创建
create or replace package body package_name
is | as
package_body
end package_name;

package_body : 用于定义过程和函数代码

3.4.3 包的使用

begin
	package_name.object_name;
end;

package_name : 包名

objec_name : 包方法或对象

3.4.3 示例
-- 创建程序包
create or replace package body user_ls.pkg_test
is
    -- 创建存储过程
	procedure prc_getCourse
    	(
			c_id in user_ls.courses.id%type,
			c_name out user_ls.course.cname%type,
			c_credit out user_ls.course.credis%type,
			c_stucount out number
		)
	is
	-- 存储过程执行方法
	begin 
		select cname,credits,count(sc.student_id)
		into c_name,c_credit,c_stucount
		form user_ls.courses c, user_ls.sc sc
		where c.course_id = sc.course_id and c.course_id = c_id
		group by c.course_id,cname,credits; -- group by后面与select 列名保持一致
 	end prc_getCourse;

   -- 创建函数
   function fn_maxgrade(f_c_id in user_ls.sc.course_id%type)
		return number
		is
		max_grader number;
	-- 函数执行方法
   begin
		select max(grade) into max_grade
		from user_ls.sc
		where course_id = f_C_id;
		return(max_grade);
   end fn_maxgrade;
end pkg_test;


-- 使用包函数和过程
declare
	c_id in user_ls.courses.id%type;
	c_name out user_ls.course.cname%type;
	c_credit out user_ls.course.credis%type;
	c_stucount out number;
	f_c_id user_ls.sc.courtse_id%type;
	max_grade number;
begin
	c_id := '001';
	f_c_id := '0001';
	user_ls okg_test.prc_getCourse(c_id,c_name,c_credit,c_stucount);
	max_grade := user_ls.pkg_test.fn_maxgrade(f_c_id);
	dbms_output.put_line('课程信息:');
	dbms_output.put_line('-----------------------------------');
	dbms_output.put_line('课程名称:' || c_name);
	dbms_output.put_line('课程学分:' || c_credit);
	dbms_output.put_line('选课人数:' || c_stucount);
	dbms_output.put_line('课程号为:' || f_c_id|| '的最高分是' || max_grade);
	dbms_output.put_line('-----------------------------------');
end;
3.4.4 获取有关包中函数和过程的信息
-- 从user_procedures中检索pkg_course_count_maxgrd的object_name 和 procedure_name列的信息
select object_name,procedure_name
from user_procedures
where object_name = 'pkg_course_count_maxgrd'
3.4.5 删除包
drop package package_name;
3.4.6 内置包
包名称描述
DBMS_ALTER数据库报警,允许会话间通信
DBMS_JOB任务调度服务
DBMS_LOB大型对象操作
DBMS_OUTPUT实现基本的输入输出功能
DBMS_PIPE数据库管道,运行会话期间通信
DBMS_SQL执行动态SQL,执行DDL语句
DBMS_FILE对操作系统文件进行读、写等操作

group by后面与select 列名保持一致
end prc_getCourse;

– 创建函数
function fn_maxgrade(f_c_id in user_ls.sc.course_id%type)
return number
is
max_grader number;
– 函数执行方法
begin
select max(grade) into max_grade
from user_ls.sc
where course_id = f_C_id;
return(max_grade);
end fn_maxgrade;
end pkg_test;

– 使用包函数和过程
declare
c_id in user_ls.courses.id%type;
c_name out user_ls.course.cname%type;
c_credit out user_ls.course.credis%type;
c_stucount out number;
f_c_id user_ls.sc.courtse_id%type;
max_grade number;
begin
c_id := ‘001’;
f_c_id := ‘0001’;
user_ls okg_test.prc_getCourse(c_id,c_name,c_credit,c_stucount);
max_grade := user_ls.pkg_test.fn_maxgrade(f_c_id);
dbms_output.put_line(‘课程信息:’);
dbms_output.put_line(’-----------------------------------’);
dbms_output.put_line(‘课程名称:’ || c_name);
dbms_output.put_line(‘课程学分:’ || c_credit);
dbms_output.put_line(‘选课人数:’ || c_stucount);
dbms_output.put_line(‘课程号为:’ || f_c_id|| ‘的最高分是’ || max_grade);
dbms_output.put_line(’-----------------------------------’);
end;


#### 3.4.4 获取有关包中函数和过程的信息

```sql
-- 从user_procedures中检索pkg_course_count_maxgrd的object_name 和 procedure_name列的信息
select object_name,procedure_name
from user_procedures
where object_name = 'pkg_course_count_maxgrd'
3.4.5 删除包
drop package package_name;
3.4.6 内置包
包名称描述
DBMS_ALTER数据库报警,允许会话间通信
DBMS_JOB任务调度服务
DBMS_LOB大型对象操作
DBMS_OUTPUT实现基本的输入输出功能
DBMS_PIPE数据库管道,运行会话期间通信
DBMS_SQL执行动态SQL,执行DDL语句
DBMS_FILE对操作系统文件进行读、写等操作
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值