Oracle


1. Oracle的使用
1.1. SQLPLUS的命令
初始化表的位置:
set NLS_LANG=american_america.us7ascii (设置编码才可以使用下面脚本)
cd $ORACLE_HOME/rdbms cd demo summit2.sql
*********************************
我们目前使用的是oralce 9i 9201 版本
select * from v$version;
恢复练习表命令:
sqlplus **/** @summit2.sql //shell要在这个文件的位置。
登陆oracle的命令:
sqlplus 用户名/密码
show user 显示当前登陆的身份.
set pause on
set pause off 分页显示.
oracle中默认日期和字符是左对齐,数字是右对齐
table or view does not exist ; 表或示图不存在
edit 命令用于自动打开vi修改刚修执行过的sql的命令。
修改方法二:
l 3 先定位到行 c /旧串/新串
执行出错时,利用错误号来查错误:
!oerr ora 942 (装完系统后会装一个oerr工具,用于通过错误号来查看错误的具体信息)
想在sql中执行unix命令时,把所有的命令前加一个!就可以, 或者host( 用于从sql从切换至unix环境中去)
/*** 初次使用时注意 ****
运行角本时的命令:
先切换到unix环境下,cd $oracle_home cd sqlplus cd demo 下面有两个角本建表语句。
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 2 页
@demobld.sql
sqlplus nanjing/nanjing @demobid.sql 直接运行角本,后面跟当前目录或者是绝对路径
保存刚才的sql语句: save 命令第二次保存时要替换之前的角本 save 文件名 replace
把刚才保的sql重新放入 buffer中
spool on 开启记录
spool off 关闭记录
spool 文件名此命令会把所有的操作存在某个文件中去
常见缩写:
nls national language support 国家语言支持
1.2. SQL的结构
|DDL 数据库定义
|DML 数据库管理
SQL――Commit rollback
|DCL 数据库控制
|grant+revoke 权限管理
表分为:系统表(数据字典),用户表
注:知道数据字典可以更便于使用数据库。
1.3. SQL语句
1.3.1. 纵向投影操作 select
select * from student;
select name||’(‘||id||’)’ EMPLOYEE from employee;
select name,salary*13 from employee;
NVL function
如果原来的数值是null的话,由指定数值替代。
select last_name,title,salary*NVL(commission_pct,0)/100 COMM from s_emp;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 3 页
1.3.2. column使用
column(col) columnName clear/format/heading/justify format
column salary format $9999999.00 设置数字显示形式
column name fromat a15; 设置字符串显示15个字符
column salary justify left/right/center 输出格式
column salary heading text 设置显示的字段名
column clear 清除格式
column last_name;显示该字段名所用的格式
column salary justify left format $99,999.00 ( 定义工资的显示形式 )
1.3.3. order by
ORDER BY 排序升序和降序 ASC 升序(默认) DESC 降序
select * from s_emp order by dept_id , salary desc
部门号升序,工资降序
关键字distinct也会触发排序操作。
select * from employee order by 1; //按第一字段排序
NULL被认为无穷大。order by 可以跟别名。
1.3.4. where 选择操作(横向投影)
where 条件一定是根据某个字段来进行过滤操作.
select * from s_emp where dept_id=42; 查看部门号为42的所有员工
select * from s_emp where salary>1000 查看工资高于1000的所有员工
select salary from s_emp where first_name='Geroge' 找出名字为Geroge的员工的工资数
select table_name from user_tables where table_name='S_EMP'; 查某个具体表名时,表名的字符串必须要为大写
或者采用 upper(table_name)
select * from user_talbes where table_name like ‘s/_%’ escape ‘/’;
使用转义字符对关键字进行转义。
逻辑运算:
BETWEEN AND 在什么之间
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 4 页
NOT BETWEEN AND 注意区间:[ ]是一个闭区间
IN( LIST) 在某个集合中
NOT IN (list) 空值会有影响 (等于list其中任何一个就行,
为提高效率常把比例高的放在前面)
LIKE 模糊配置
NOT LIKE 通配比较
IS NULL 是空
AND
OR
NOT
练习3:(查出s_emp表中所有员工的一年的总收入)
select first_name , salary*12*( 1+nvl(commission_pct/100 , 0 ) ) " year salary " from s_emp;
nvl函数专用于处理空值的影响.
练习4:(找出表名以S_开头的所有表)对于一些特殊字符,要用到escape转义,并不是一定要用/,escape后面定义是什么字符为转义字符,那就用哪个字符
select table_name from user_tables where table_name like 'S/_%' escape '/';
1.3.5. 单行函数
单行函数: (dual 哑表 )
字符函数:
lower 转小写 select lower('SQLPLUS') from dual;-->对纯字符串处理的时候
upper 转大写 select upper('sqlplus') from dual;
initcap 首字符大写 select initcap('tarena') from dual;
concat 连接字符串 select concat(first_name , last_name) from s_emp;等效于||
substr 求子串 select substr('tarenasd0603' ,1,6) from dual; (取前六个字符) select substr('tarenasd0603',-2) from dual; (取后两个字符)
length 求字符长度
select length('tarena') from dual;
nvl 空值函数两个参数的类型要匹配,统一的,表示:如果有,则返回前面的参数,如果没有就返回后面的参数
eg:select first_name,salary from s_emp where lower(first_name)='george';
select first_name , substr(first_name , -2 ) from s_emp; (查出s_emp表中所有用户名字的最后两个字符)
默认的是从左向右,如果是-2则表示从右向左数
练习5: select first_name , salary from s_emp where
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 5 页
lower(first_name)='george';
数值函数:
round 函数(四舍五入) select round(45.935, 2) from dual; 不带参数时默认为0位小数
trunc 函数(截取,不管后面的数字) select trunc(45.995, 1) from dual;
日期函数:
oracle数据库中存放时间格式的数据,是以oracle特定的格式存贮的,占7个字节,与查询时显示的时间格式无关,具体哪个字节表示什么,我不太清楚,请高手补充。存贮的时间包括年月日时分秒,最小精度为秒,不存贮秒以下的时间单位。因此在一些前台支持毫秒级的程序(如PB客户端程序)连接到oracle数据库时应注意这点。查询时显示的时间格式,由会话环境决定,或者由用户定义,与数据库无关。
select sysdate from dual; 从伪表查系统时间,以默认格式输出。
sysdate+(5/24/60/60) 在系统时间基础上延迟5秒
sysdate+5/24/60 在系统时间基础上延迟5分钟
sysdate+5/24 在系统时间基础上延迟5小时
sysdate+5 在系统时间基础上延迟5天
所以日期计算默认单位是天
内置函数:
months_between(sysdate,addmonth(sysdate,5)) //两个月有多少天。
add_months(sysdate,-5) 在系统时间基础上延迟5月
add_months(sysdate,-5*12) 在系统时间基础上延迟5年
last_day(sysdate) 一个月最后一天
next_day(sysdate,’Friday’) 下个星期星期几。
round (sysdate,’day’) 不是四除五入了,是过了中午留下,不过的略掉
trunc(sysdate,’month’) 不到一月都省略
例子:
上月末的日期:select last_day(add_months(sysdate, -1)) from dual; 本月的最后一秒:select trunc(add_months(sysdate,1),'month') - 1/24/60/60 from dual 本周星期一的日期:select trunc(sysdate,'day')+1 from dual
年初至今的天数:select ceil(sysdate - trunc(sysdate, 'year')) from dual;
格式转换函数:
to_char显示日期:
从数字转化为char to_char(date,'格式')
从日期转化为char to_char(date, 'fmt' )
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 6 页
yyyy
2007 年份
year
two thousand seven 年份
mm
03 (格式缩写显示也缩写)
month
march 月份
dy
fri 星期几缩写
day
Friday 星期几
dd
16 一个月第几天
mi
30 分钟
ss
35 秒钟
hh
18 小时
rr
07 年 最近时间
yy
07 年当前世纪年份
select to_char(sysdate, 'yyyy mm dd hh24:mi:ss') from dual;
select to_char(sysdate, 'fmyyyy mm dd hh24:mi:ss') from dual;
查出三月分入职的员工:
select first_name,start_date from s_emp where to_char(start_date,'mm')='03';
to_date表达日期:
字符转日期
select to_date('2000 11 20', 'yyyy mm dd ') from dual;
select round(to_date('10-OCT-06' ,'dd-mon-RR') ) from dual;
to_number
字符转数字
select to_number('10') from dual ;
函数、表达式、隐式数据类型转换会导致索引用不上,where条件后面只能放单行函数,它起了一个过滤的的作用。
1.3.6. 组函数
group by 分组子句 对分组后的子句进行过滤还可以用having 条件 对分组后的条件进行过滤 where 是对记录进行过滤
avg(distinct | all )求平均值
count(distinct | all )统计
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 7 页
max(distinct | all ) 求最大值
min(distinct | all )求最小值
sum(distinct | all ) 求和
(所有组函数会忽略空值 , avg sum只能作用于数字类型)
求有提成员工的提成的平均值;
select avg(nvl(commission_pct ,0 ) ) from s_emp;
有多少人有提成:
select count( commission_pct ) from s_emp ;
count(*) 用于统计记录数:
select sum(commission_pct)/ count(*) from s_emp;
员工分部在多少个不同的部门:count 默认为作all的动作
select count(dept_id) from s_emp;
select count(distinct dept_id) from s_emp;
求各个部门的平均工资:group by 子句也会触发排序
select dept_id , avg(salary) aa from s_emp group by dept_id order by aa ; //对平均工资排序
select dept_id , avg(salary) aa from s_emp group by dept_id;
注意:group by 子句后面跟有条件只能是组函数查询的结果中的字段,所以我们会人为在结果要加入一些group by 要用的字段,如:dept_id可能不想要。
select region_id , count(*) from s_dept 此句会有错,count(*)是单组分组函数,如果加上group by region_id 就是找出同地区的部门数量。
select max(region_id) , count(*) from s_dept; (强制语法上可以正确,但是不能保证结果也会正确)
求各个部门不同工种的平均工资:
select dept_id , title, avg(salary) from s_emp group by dept_id , title ;
哪些部门的平均工资比2000高:
select dept_id, avg(salary) aa from s_emp group by (dept_id) having avg(salary)>2000;
除了42部门以外的部门的平均工资:
select dept_id , avg(salary) from s_emp group by (dept_id ) having dept_id!=42;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 8 页
select dept_id , avg(salary) from s_emp where dept_id!=42 group by (dept_id ) ;(此种sql效率要高,先过滤) 再计算)
where 单行函数。
having 组函数。
求各个部门的平均工资:
// 这样统计不详细
select max(d.name) , avg (s.salary) from s_emp s, s_dept d where s.dept_id=d.id group by d.name;
//****这问题很经典,为了过 oracle sql 语法关而写max(d.name) ***
select max(d.name) , avg(e.salary) , max(r.name) from s_emp e, s_dept d , s_region r where e.dept_id = d.id and d.region_id=r.id
group by d.id ;
1.3.7. 多表连接
多表连接操作:
两表没有任何关联时会产生迪卡尔机:
select first_name , name from s_emp , s_dept;
1) 等值连接:
练习一:查看员工的姓名和员工部门号:(要考虑到表中实际数据中空值的影响)
select first_name , name from s_emp e, s_dept d where e.dept_id=d.id;
同时起了别名
select first_name , name from s_emp e, s_dept d where e.dept_id=d.id and
e.first_name='George';
具体到哪个人所在的部门
表的两边有空值的话,不会显示出来。
练习二:每个员工所在的部门和部门所在的地区
select first_name , s_dept.name, s_region.name from s_emp, s_dept, s_region where
s_emp.dept_id=s_dept.id
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 9 页
s_dept
等价于
select fi
from s_emp e,s_dept d,s_region r
where e.dept_id=d.id and d.region_id=r.id;
等值连接:
select a.ename , a.sal, b.grade from emp a , s
select a.ename , a.sal, b.grade from emp a , salgrade b where a.sal>=b.losa
and a.sal<=b.hisal;
当一个表的插入行之间有了关系时就发生了
select first_name , manager_id from s_emp; l
查出所有员工的部门领导的名称:( 这种sq会少一条记录,总经理没有被配置上)
select
e.manager_id=m.id; //关键是同一张表用不同的别名
(防止空值忽略,用(
加(+)一个记录都不能少; select e.first_name , m.first_n
e.manager_id=m.id(+);
+号放在哪边就表示在哪
这个例子中的领导有可能会没有(最高领导就再没有领导了,所以就+号放在可能出现空值的一边)
标准写法:
显示没有员工的部门
select distinct d.name
from
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 10 页
where
e.dept_id(+)=d.id
and
e.dept_id is null
显示有员工的部门:
s
from
s_emp e,s_dept d
where
e.dept_id=d.id
关于子查询找出所有员工中
select first_name, sala min(salary) from s_emp)
select max(first_name), min(sala
//
先运行子查询再运行主查询,子查询一般出现在运算符的
右边。

多值运算符:可以对两个以上的值进行操作查询谁跟
1.先找出Smith干什么工作
select title from s_emp where
last_name='Sm
2.再在所有数据中找和Smith
下种写法可能还存在bug,没有考虑到数据的全面性
selecrom se='Sm
_emp where last_namith' ) and last_name <> 'Smith' ;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 11 页
select last_name , title from s_emp where title in ( select title from s_emp where last_name='Smith' ) and last_name <> 'Smith
使用子查询时应注意: 单行
returns more than one value 查出哪些员工的工资比平均工资低:
from s_emp e
where
e.salary<
(select avg( nv
from s_
哪些部门的平均工资比所有部门的平均工资要低:
第一步先查出各个部门的平均工资:
select min(a
第二步再查出哪个部门的工资是最低的:
avg(salary) = (select min(avg(salary) ) from s_emp grou select deptno from dept where deptno not in ( select
deptno from
哪些人是普通员工:(用
select first_name,last_name from s_emp where id not in
(select distinct(manager_id) from s_emp where
1.3.9. 语言环境
zh_CN.hp15CN $ echo $NLS_LANG
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 12 页
1
开发流程先进行需求分析,进行系统设计,建表,再进行
把软件设计模型转化为数据中的表,设计时要考虑性能的设计
第一范式:最简单的一种建方式,一张表只有一个主键。

第三范式:表连接存在的原因,两张表,其中一张表引用其
约束:

primary key (pk)
foregin key (fk) 外键
unique key (uk) 唯一可以为空
not null
数据库设计时的注意:
索引: 为了
考虑表点用的物理空间:
考虑表之间的关系:
一对多关系: 利用FK+PK
一对一关系: 可以利
多对多关系: 通过中间增加一个附加表来实现,附加
联合起来的主键唯一。
1
DDL (DataBase Defind L
view(示图)
sequence(序
index(索引)
创建表语句:
c
schema 默认
数据类型: 表名的命令规则: 首字母为字母,不得超过30个字符
char(size)
varchar2(size) 可变长按实际的字节占用空间
number 所有的数字类型都称为number
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 13 页
number(n, m ) n------n位宽度 m-----小数点后的宽度
number(2,4)小数点后4 位,有效位2位 v
values(0.01)这样出错
LONG 2GB 大文本一个表最我只允许定义一个LONG类型(不建议使用) CLOB 大对象形式
BLOB 存二进制大对象(声音,图像之类)
default 作用演示:
c
1
主键约束的定义:
create table test(c num
create table test( c1 number constraints pkc1 primary key
此约束有名字: pkc1
create table test(c num
用表级约束可以实现联合主键
外键约束的定义:(先定义父表,
carete table parent(c1 number primary key
parent(c1)); //列约束
create table child( c number primary key , c2 number , foreign key(c2 references parent(c1));
on delete cascade (
create table child(id number, parent_id number(10) constraint child_fk references
parent(id) ) on delete cascade
create table child(id number, parent_id number(10) constraint child_fk references parent(id) ) on delete set null
不给约束起名字时,
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 14 页
不能重名) 定义一个约束
列级约束 表级约束

not nul

check 约束:
create table
此表中要求c1的值必须要大于1000 才为有效值 .

= 42; 只取要表结构,不想要表中数据的建表方式:
o
这是一个小技巧,利用永不等式提取零条数据,在JDBC的学习中会用到 where
1=1 的形式,注意体会)

desc user_constraints;(这个数据字典
select constraint_name, constraint_types
table_name='S_EMP'; P pk
R fk
C chec
U UK
V 这种
束) O
非空约束和CHECK都是用

ns;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 15 页
select column_name, position from user_cons_columns where constraint_name='S_EMP_ID_PK' ;
position 的含义:联合主键,约束名一样。
user_constraints user_cons_columns 两张表的约束名相等,表名相等,两张表一关联就可以查出所需的信息。
select constraint_name , r_constraint_name from user_constraints where constraint_type='R' and table_name='S_EMP' ;
数据库建立时,数据字典就会建好。
user_constraints; 自己拥有的
all_constraints; 你自己拥有的加上你可以访问的
dba_constraints 所有的
查看当前数据库数据字典的字典(这个示图很重要)
desc dict;
select table_name form dict where table_name like '%cons%;
示图:
user_objects; user_tables;
select distinct object_type from user_objects;
1.3.13. 介绍事务的概念:
commit 提交,此时说明前面所有语句都成功执行
rollback 回退操作,此时会恢复至上一次提交时的状态。
savepoint 设置保存点
注意 insert into 后面可以跟子查询
insert into s_emp_42 select * from s_emp where dept_id =42;
UPDATE 修改字段值:
update s_emp set dept_id =10 where id =2 ;
update s_emp set commission_pct =10 ;
没有where条件时说明是改表中所有的值.
注意:如有外键引用时常会出现外键引用值没有找到等错误?
delete 删除记录命令语法:
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 16 页
delete from s_emp where dept_id=42;
delete form s_emp ; 没有where条件时说明删除表中所有的值
注意:如有外键引用时,删除一张表时常会出现不能删除的情况,
原因一 是因为此时正在有人操作表中记录
原因二 此表有其他的表引用,没能设及联删除:
delete 删除一张大表时空间不释放,非常慢是因为占用大量的系统资源,支持回退操作,空间还被这张表占用着。
truncate table 表名 (删除表中记录时释放表空间)
DML 语句:
表级共享锁: 对于操作一张表中的不同记录时,互不影响
行级排它锁:对于一行记录,oracle 会只允许只有一个用户对它在同一时间进行修改操作
wait() 等到行级锁被释放,才进行数据操作
drop一张表时也会对表加锁,DDL排它锁,所以在删除一张表时如果当前还有用户操作表时不能删除表
alter table 命令用于修改表的结构(这些命令不会经常用):
增加约束:
alter table 表名 add constraint 约束名 primary key (字段);
解除约束:(删除约束)
alter table 表名 drop primary key(对于主键约束可以直接用此方法,因为一张表中只有一个主键约束名, 注意如果主键此时还有其它表引用时删除主键时会出错)
alter table father drop primary key cascade ; (如果有子表引用主键时,要用此语法来删除主键,这时子表还存在只是子表中的外键约束被及联删除了)
alter table 表名 drop constraint 约束名;
(怎样取一个约束名:1、人为的违反约束规定根据错误信息获取!
2、查询示图获取约束名!)
alter table 表名 disable from primary key ; (相当于把一个表的主键禁用)
alter table 表名 enable primary key ;(enable 时会自动去检查表的记录是不是符合要求,如果有脏数据时必须要先删除脏数据才可以 enable)
*******************************************************************
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 17 页
增加字段:
alter table 表名 add(字段字字段类型)
删除字段:
alter table 表名 drop(字段)
alter tbale 表名 drop column 字段 ; (8i 以后才支持)
给列改名:920才支持
alter table 表名 rename column 旧字段名 to 新字段名;
修改字段
(此时应注意的问题,更改时要看具体值情况之间的转达换, 改为字符类型时,必须要为空)
alter table 表名 modify( 字段,类型)
更改表中的字段:
update 表名 set 字段= 值 where 条件
更改表名
rename 旧表名 to 新表名;
删除表:
trucate table 表名:(表结构还在,数据全部删除,释放表所占的空间,不支持回退,常用删除大表)
1.3.14. oralce中产生序列(sequence):
create sequence 序列名;
(不带参数时默认为从1 开始每次递增 1,oracle中为了提高产生序列的效率一般一次性产生20个序列放入当前会话的序列池中备用以加快效率,序列会出现不连续的动作回退操作不会影响序列取值)
sequence 的参数:
increment by n 起始值, start with n 递增量, maxvalue n 最大值, minvalue n 最小值,cycle | no cycle 轮回, cache n 绶存(第一次取时会一次取多少个id存起来)
查看 sequence 示图:
desc user_sequences ;
select sequence_name , cache_size , last_number from user_sequences where sequence_name like 's_';
select 序列名.currval from dual 查看当前的序列数
第一次执行这个命令会出错,因为还没有序列号放进序列池中,也就是说
currval读取的是序列池中的数值。
select 序列名.nextval from dual 查看下一个序列数,它会自动给当前的序列加1,实际上是给序列池中的数值加一,而序列表中加的是缓存的值。
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 18 页
清空当前会话的内存:
alter system flush shared_pool;(执行此命令要有DBA权限,一般用户执行出错)
修改序列:(此命令不常用,只需了解就行不必深究)
alter sequence 序列名修改项;
删除序列sequence
drop sequence 序列名;
1.3.15. 创建示图
creating views(属于了解知识)
desc user_views;
select text from user_views where view_name='TEST1_V1' ;
示图就相当于一条select 语句,定义了一个示图就是定义了一个sql语句,示图不占空间,使用view 不会提高性能,但是能简单化sql语句
(扩展知识: oracle 8i 以后的新示图)MV 物化视图(占存储空间,把select 结果存在一个空间,会提高查询视图,增强实时性,但是存在刷新问题, 主要应用在数据仓库中用要用于聚合表)
使用示图的好处:控制数据访问权限.
如何创建一个示图:
create or replace views test_vi as select * from test1 where c1=1;
此时往表test1(base table 基表)中插入数据时:表中没能变化,示图中的数据发生改变
从示图中插数据时相对应的表会发生改变:
往示图中插数据时,会直接插进基表中,查看示图中的数据时,相当于就是执行创建时的select语句。
简单示图:能进行DML操作。
复杂示图:来源于多张表,不能执行DML操作。
1.3.16. 关于利用rownum分页显示
rownum 有个特点要么等于1 要么小于某个值, 不能直接等于某个值, 不能大于某个值。rownum常用于分页显示。
练习:查询出第5条数据和第10条数据之间:
select first_name , rnum from ( select rownum rnum , first_name from s_emp where rownum <=10 ) where rnum between 5 and 10 ;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 19 页
分面显示:
SELECT * FROM (SELECT a.*, rownum r FROM S_EMP a ) WHERE r between 5 AND 10;
练习:哪些员工的工资比本部门的平均工资高?
select first_name , salary , avgsal from s_emp e , ( select dept_id , avg (salary ) avgsal from s_emp group by dept_id ) a where e.dept_id =a.dept_id and e.salary > a.avgsal;
在示图上加一个 with check option 就相当于给示图加上了约束
create view test_v as select * from test where c =1 with check option ;
create view test_v as select * from test with read option; 定义在视图上的约束,只读。
同义词:相当于别名的作用(***只需了解***)系统自建的同义词: user_tables
create synonym asd_s_emp for asd_0607.s_emp ;
目的就是为了给asd_0607_s_emp表起另一个代替的名称asd.s_emp;注意这个同义词只能自己使用;
create public synonym p_s_emp fro asd_0607.s_emp; 创建公共的同义词,但是要权限.
删除同义词:
drop synonym 同义词名称
1.3.17. 创建索引
Creating indexes(概念很重要对系统的性能影响非常大)
建索引的目的就是为了加快查询速度,使表中数据在做insert语句时就进行排序。
索引是DML语句触发的,系统自动运行,也可以强制使用索引。
索引的结构
key | rowid
索引就相于一本的书的目录。索引点系统空间,属于表的附属物。删除一个表时,相对应的索引也会删除。truncate 表时索引结构在,但是数据不存在。
full table scan 全表扫描
用索引就是为了快速定位数据:(理解时就以字典的目录为例)
查看表的rowid:
select rowid , first_name from s_emp;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 20 页
rowid 定义的信息有: object block table
每条记录都有自己的rowid ,rowid记录了这条记录在数据库中的位置,可以快速读取。
索引由谁创建:用户,建索引后会使DML操作效率慢,但是对用户查询会提高效率,这就是我们建索引的最终目的,
创建一个索引:
create index 索引名 on 表名 ( 字段名);
create insex testindex on test(c1, c2);
哪些字段应该建索引:
经常要用where的子句的地方,所以要用索引.用不用索引,关键要看所查询的数据与所有数据的百分比,表越大,查询的记录越少,索引的效率最高.
替换变量:用&符号来定义替换变量支持交互性提示,对于字符性的数字,一定要写在单引号之间
set verify on
set verify off;
相当于开关变量,用于控制是否显示新旧的sql语句
select id ,last_name ,salary from s_emp where title='&job_title';
更改交互的提示信息:
accept p_dname prompt ' 提示信息';
定义变量:
define p_dname='abc';
分页的实现语句:(可以正常运行)
select * from ( select rownum rnum , a.* from (select * from s_emp) a ) where rnum between 5 and 10 ;
1.4. SQL语句使用技巧
1.删除表空间
DROP TABLES
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 21 页
3.删除表的注意事项
在删除一个表中的全部数据时,须使用TRUNCATE TABLE 表名;因为用DROP TABLE,DELETE * FROM 表名时,TABLESPACE表空间该表的占用空间并未释放,反复几次DROP,DELETE操作后,该TABLESPACE上百兆的空间就被耗光了。
4.having子句的用法
having子句对group by子句所确定的行组进行控制,having子句条件中只允许涉及常量,聚组函数或group by 子句中的列。
5.外部联接"+"的用法
外部联接"+"按其在"="的左边或右边分左联接和右联接.若不带"+"运算符的表中的一个行不直接匹配于带"+"预算符的表中的任何行,则前者的行与后者中的一个空行相匹配并被返回.若二者均不带’+’,则二者中无法匹配的均被返回.利用外部联接"+",可以替代效率十分低下的 not in 运算,大大提高运行速度.例如,下面这条命令执行起来很慢
用外联接提高表连接的查询速度
在作表连接(常用于视图)时,常使用以下方法来查询数据:
SELECT PAY_NO, PROJECT_NAME FROM A WHERE A.PAY_NO NOT IN (SELECT PAY_ NO FROM B WHERE VALUE >=120000);
---- 但是若表A有10000条记录,表B有10000条记录,则要用掉30分钟才能查完,主要因为NOT IN要进行一条一条的比较,共需要10000*10000次比较后,才能得到结果。该用外联接后,可以缩短到1分左右的时间:
SELECT PAY_NO,PROJECT_NAME FROM A,B WHERE A.PAY_NO=B.PAY_NO(+) AND B.PAY_NO IS NULL AND B.VALUE >=12000;
6.set transaction命令的用法
在执行大事务时,有时oracle会报出如下的错误:
ORA-01555:snapshot too old (rollback segment too small)
这说明oracle给此事务随机分配的回滚段太小了,这时可以为它指定一个足
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 22 页
够大的回滚段,以确保这个事务的成功执行.例如
set transaction use rollback segment roll_abc; delete from table_name where ... commit;
回滚段roll_abc被指定给这个delete事务,commit命令则在事务结束之后取消了回滚段的指定.
7.数据库重建应注意的问题
在利用import进行数据库重建过程中,有些视图可能会带来问题,因为结构输入的顺序可能造成视图的输入先于它低层次表的输入,这样建立视图就会失败.要解决这一问题,可采取分两步走的方法:首先输入结构,然后输入数据.命令举例如下 (uesrname:jfcl,password:hfjf,host sting:ora1,数据文件:expdata.dmp):
imp jfcl/hfjf@ora1 file=empdata.dmp rows=N imp jfcl/hfjf@ora1 file=empdata.dmp full=Y buffer=64000 commit=Y ignore=Y
第一条命令输入所有数据库结构,但无记录.第二次输入结构和数据,64000字节提交一次.ignore=Y选项保证第二次输入既使对象存在的情况下也能成功.
select a.empno from emp a where a.empno not in (select empno from emp1 where job=’SALE’);
倘若利用外部联接,改写命令如下:
select a.empno from emp a ,emp1 b where a.empno=b.empno(+) and b.empno is null and b.job=’SALE’;
可以发现,运行速度明显提高.
8.从已知表新建另一个表:
CREATE TABLE b AS SELECT * (可以是表a中的几列) FROM a WHERE a.column = ...;
9.查找、删除重复记录:
法一: 用Group by语句此查找很快的
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 23 页
select count(num), max(name) from student --查找表中num列重复的,列出重复的记录数,并列出他的name属性group by num having count(num) >1 --按num分组后找出表中num列重复,即出现次数大于一次delete from student(上面Select的)
这样的话就把所有重复的都删除了。-----慎重
法二:当表比较大(例如10万条以上)时,这个方法的效率之差令人无法忍受,需要另想办法:
---- 执行下面SQL语句后就可以显示所有DRAWING和DSNO相同且重复的记录
SELECT * FROM EM5_PIPE_PREFAB WHERE ROWID!=(SELECT MAX(ROWID) FROM EM5_PIPE_PREFAB D --D相当于First,Second WHERE EM5_PIPE_PREFAB.DRAWING=D.DRAWING AND EM5_PIPE_PREFAB.DSNO=D.DSNO);
---- 执行下面SQL语句后就可以刪除所有DRAWING和DSNO相同且重复的记录
DELETE FROM EM5_PIPE_PREFAB WHERE ROWID!=(SELECT MAX(ROWID) FROM EM5_PIPE_PREFAB D WHERE EM5_PIPE_PREF
AB.DRAWING=D.DRAWING AND EM5_PIPE_PREFAB.DSNO=D.DSNO);
10.返回表中[N,M]条记录:
取得某列中第N大的行
select column_name from (select table_name.*,dense_rank() over (order by column desc) rank from table_name) where rank = &N;
假如要返回前5条记录:
select * from tablename where rownum<6;(或是rownum <= 5 或是rownum != 6)
假如要返回第5-9条记录:
select * from tablename where …
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 24 页
and rownum<10 minus select * from tablename where … and rownum<5 order by name
选出结果后用name排序显示结果。(先选再排序)
注意:只能用以上符号(<、<=、!=)。
select * from tablename where rownum != 10;返回的是前9条记录。
不能用:>,>=,=,Between...and。由于rownum是一个总是从1开始的伪列,Oracle 认为这种条件不成立,查不到记录.
另外,这个方法更快:
select * from ( select rownum r,a from yourtable where rownum <= 20 order by name ) where r > 10
这样取出第11-20条记录!(先选再排序再选)
要先排序再选则须用select嵌套:内层排序外层选。
rownum是随着结果集生成的,一旦生成,就不会变化了;同时,生成的结果是依次递加的,没有1就永远不会有2!
rownum 是在查询集合产生的过程中产生的伪列,并且如果where条件中存在rownum 条件的话,则:
1: 假如 判定条件是常量,则:
只能 rownum = 1, <= 大于1 的自然数, = 大于1 的数是没有结果的, 大于一个数也是没有结果的
即 当出现一个 rownum 不满足条件的时候则查询结束 this is stop key!
2: 当判定值不是常量的时候
若条件是 = var , 则只有当 var 为1 的时候才满足条件,这个时候不存在 stop key ,必须进行 full scan ,对每个满足其他where条件的数据进行判定
选出一行后才能去选rownum=2的行……
11.快速编译所有视图
---- 当在把数据库倒入到新的服务器上后(数据库重建),需要将视图重新编译一遍,因为该表空间视图到其它表空间的表的连接会出现问题,可以利用PL/SQL的语言特性,快速编译。
SQL >SPOOL ON.SQL SQL >SELECT ‘ALTER VIEW ‘||TNAME||’
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 25 页
COMPILE;’ FROM TAB; SQL >SPOOL OFF
然后执行ON.SQL即可。
SQL >@ON.SQL
当然,授权和创建同义词也可以快速进行,如:
SQL >SELECT ‘GRANT SELECT ON ’ ||TNAME||’ TO USERNAME;’ FROM TAB; SQL >SELECT ‘CREATE SYNONYM ‘||TNAME||’ FOR USERNAME.’||TNAME||’;’ FROM TAB;
12.读写文本型操作系统文件
---- 在PL/SQL 3.3以上的版本中,UTL_FILE包允许用户通过PL/SQL读写操作系统文件。如下:
DECALRE FILE_HANDLE UTL_FILE.FILE_TYPE; BEGIN FILE_HANDLE:=UTL_FILE.FOPEN( ‘C:/’,’TEST.TXT’,’A’); UTL_FILE.PUT_LINE(FILE_HANDLE,’ HELLO,IT’S A TEST TXT FILE’); UTL_FILE.FCLOSE(FILE_HANDLE); END;
13.在数据库触发器中使用列的新值与旧值
---- 在数据库触发器中几乎总是要使用触发器基表的列值,如果某条语句需要某列修改前的值,使用:OLD就可以了,使用某列修改后的新值,用:NEW就可以了。如:OLD.DEPT_NO,:NEW.DEPT_NO。
14.数据库文件的移动方法
当想将数据库文件移动到另外一个目录下时,可以用ALTER DATABASE命令来移动(比ALTER TABLESPACE适用性强):
1. 使用SERVER MANAGER关闭实例.
SVRMGR > connect internal; SVRMGR > shutdown; SVRMGR >exit;
2. 使用操作系统命令来移动数据库文件位置(假设这里操作系统为SOLARIS
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 26 页
2.6). 在UNIX中用 mv命令可以把文件移动到新的位置,
#mv /ora13/orarun/document.dbf /ora12/orarun
3. 装载数据库并用alter database命令来改变数据库中的文件名.
SVRMGR > connect internal; SVRMGR > startup mount RUN73; SVRMGR > alter database rename file > ‘/ ora13/orarun/document.dbf’ > ‘/ ora12/orarun/document.dbf’;
4. 启动实例.
SVRMGR > alter database open;
15.连接查询结果:
表a 列 a1 a2
记录 1 a
1 b
2 x
2 y
2 z
用select能选成以下结果:
1 ab
2 xyz
下面有两个例子:
1.使用pl/sql代码实现,但要求你组合后的长度不能超出oracle varchar2长度的限制
create or replace type strings_table is table of varchar2(20); / create or replace function merge (pv in strings_table) return varchar2 is ls varchar2(4000); begin for i in 1..pv.count loop ls := ls || pv(i); end loop; return ls; end; / create table t (id number,name varchar2(10)); insert into t values(1,'Joan'); insert into t values(1,'Jack');
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 27 页
insert into t values(1,'Tom'); insert into t values(2,'Rose'); insert into t values(2,'Jenny'); column names format a80; select t0.id,merge(cast(multiset(select name from t where t.id = t0.id) as strings_table)) names from (select distinct id from t) t0; drop type strings_table; drop function merge; drop table t;
2.纯粹用sql:
表dept, emp
要得到如下结果
deptno, dname, employees
---------------------------------
10, accounting, clark;king;miller 20, research, smith;adams;ford;scott;jones 30, sales, allen;blake;martin;james;turners
每个dept的employee串起来作为一条记录返回
This example uses a max of 6, and would need more cut n pasting to do more than that: SQL> select deptno, dname, emps 2 from ( 3 select d.deptno, d.dname, rtrim(e.ename ||', '|| 4 lead(e.ename,1) over (partition by d.deptno 5 order by e.ename) ||', '|| 6 lead(e.ename,2) over (partition by d.deptno 7 order by e.ename) ||', '|| 8 lead(e.ename,3) over (partition by d.deptno 9 order by e.ename) ||', '|| 10 lead(e.ename,4) over (partition by d.deptno 11 order by e.ename) ||', '|| 12 lead(e.ename,5) over (partition by d.deptno 13 order by e.ename),', ') emps, 14 row_number () over (partition by d.deptno 15 order by e.ename) x 16 from emp e, dept d 17 where d.deptno = e.deptno 18 ) 19 where x = 1 20 / DEPTNO DNAME EMPS
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 28 页
------- ----------- ------------------------------------------
10 ACCOUNTING CLARK, KING, MILLER
20 RESEARCH ADAMS, FORD, JONES, ROONEY, SCOTT, SMITH
30 SALES ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD
16.在Oracle中建一个编号会自动增加的字段,以利于查询
1、建立序列:
CREATE SEQUENCE checkup_no_seq NOCYCLE MAXVALUE 9999999999 START WITH 2;
2、建立触发器:
CREATE OR REPLACE TRIGGER set_checkup_no BEFORE INSERT ON checkup_history FOR EACH ROW DECLARE next_checkup_no NUMBER; BEGIN --Get the next checkup number from the sequence SELECT checkup_no_seq.NEXTVAL INTO next_checkup_no FROM dual;
--use the sequence number as the primary key --for the record being inserted :new.checkup_no := next_checkup_no; END;
17.查看对象的依赖关系(比如视图与表的引用)
查看视图:dba_dependencies 记录了相关的依赖关系
查东西不知道要查看哪个视图时,可以在DBA_Objects里看,
select object_name from dba_objects where object_name like '%ROLE%'(假如查看ROLE相关)
然后DESC一下就大体上知道了。
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 29 页
18.要找到某月中所有周五的具体日期
select to_char(t.d,'YY-MM-DD') from ( select trunc(sysdate, 'MM')+rownum-1 as d from dba_objects where rownum < 32) t where to_char(t.d, 'MM') = to_char(sysdate, 'MM') --找出当前月份的周五的日期and trim(to_char(t.d, 'Day')) = '星期五'
--------
03-05-02
03-05-09
03-05-16
03-05-23
03-05-30
如果把where to_char(t.d, 'MM') = to_char(sysdate, 'MM')改成sysdate-90,即为查找当前月份的前三个月中的每周五的日期。
1.4.1. 建立用户
用户名: oracle
密码: oracle
sqlplus '/as sysdba'
echo $ORACLE_SID
create user nanjing identified by nanjing;
grant connect,resource,create session,create table to nanjing;
2. 数据字典的使用
1.表:
select * from cat; //显示所有用户对象。
select * from tab; //显示所有用户表。
select table_name from user_tables; //显示所有用户表
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 30 页
2.视图:
select text from user_views where view_name=upper('&view_name');
//显示某个视图
3.索引:
select index_name,table_owner,table_name,tablespace_name,status from user_indexes order by table_name;
//显示用户索引
4.触发器:
select trigger_name,trigger_type,table_owner,table_name,status from user_triggers;
//显示用户触发器
5.快照:
select owner,name,master,table_name,last_refresh,next from user_snapshots order by owner,next;
6.同义词:
select * from syn;
7.序列:
select * from seq;
8.数据库链路:
select * from user_db_links;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 31 页
9.约束限制:
select TABLE_NAME,CONSTRAINT_NAME,SEARCH_CONDITION,STATUS
from user_constraints WHERE TABLE_name=upper('&TABLE_Name');
10.本用户读取其他用户对象的权限:
select * from user_tab_privs;
11.本用户所拥有的系统权限:
select * from user_sys_privs;
12.用户:
select * from all_users order by user_id;
13.表空间剩余自由空间情况:
select tablespace_name,sum(bytes) 总字节数,max(bytes),count(*) from dba_free_space group by tablespace_name;
14.数据字典:
select table_name from dict order by table_name;
可以通过数据字典表查询其他系统表
select table_name from dict where table_name = ‘ ***%’order by table_name
15.锁及资源信息:
select * from v$lock;不包括DDL锁
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 32 页
16.数据库字符集:
select name,value$ from props$ where name='NLS_CHARACTERSET';
simplified chiniese_china.zhs16GBK 简体中午编码
17.inin.ora参数:
select name,value from v$parameter order by name;
18.SQL共享池:
select sql_text from v$sqlarea;
19.数据库:
select * from v$database
20.控制文件:
select * from V$controlfile;
21.重做日志文件信息:
select * from V$logfile;
22.来自控制文件中的日志文件信息:
select * from V$log;
23.来自控制文件中的数据文件信息:
select * from V$datafile;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 33 页
24.NLS参数当前值:
select * from V$nls_parameters;
25.ORACLE版本信息:
select * from v$version;
26.描述后台进程:
select * from v$bgprocess;
27.查看版本信息:
select * from product_component_version;
28.查询oracle中所有用户信息
select * from dba_users;
29.只查询用户和密码
select username,password from dba_users;
30.查询当前用户信息
select * from dba_ustats;
3. PL/SQL语言
Procedure Language Structure Qurrey Language――PL/SQL
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 34 页
3.1. Oracle的变量类型
数据类型
数字,字符,布尔,日期
组合类型
Record(不同数据集合),table(一张表),varray(数组)
参考型
Ref cursor, ref object_type
数字类型
Binary_integer,Dec,Float
Number
Number(3)
Number(4,3) 前面的总长,后面是小数的长度
字符类型
Char(不可变长), varchar(过时) , varchar2(现在使用) , string
Boolean,date
Declare
V_firstName varchar(20);
Declare
V_firstName students.first_name%type; ――和students.first_name的大小一致
*显示输出―――set serveroutput on
3.2. 代码注释
多行 /* */
单行 --
3.3. Type关键字:
Example 1:
Declare
V_id students.id%type:=1;
V_name students.name%type:=’mudi’;
V_age students.age%type:=24;
Begin
Dbms_ouput.put_line(v_id);
Dbms_output.put_line(v_name);
Dbms_output.put_line(v_age);
End;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 35 页
DECLARE
v_LastName S_EMP.LAST_NAME%TYPE;
v_FirstName S_EMP.FIRST_NAME%TYPE;
v_ID S_EMP.ID%TYPE;
Example 2:
BEGIN
select ID,LAST_NAME,FIRST_NAME INTO v_ID,v_LastName,v_FirstName FROM S_EMP WHERE rownum = 1;
DBMS_OUTPUT.PUT_LINE(v_ID);
DBMS_OUTPUT.PUT_LINE(v_LastName);
DBMS_OUTPUT.PUT_LINE(v_FirstName);
END;
多个TYPE类型组合使用
DECLARE
v_LastName S_EMP.LAST_NAME%TYPE;
v_FirstName S_EMP.FIRST_NAME%TYPE;
v_ID S_EMP.ID%TYPE;
BEGIN
select ID,LAST_NAME,FIRST_NAME INTO v_ID,v_LastName,v_FirstName FROM S_EMP WHERE rownum = 1;
DBMS_OUTPUT.PUT_LINE(v_ID);
DBMS_OUTPUT.PUT_LINE(v_LastName);
DBMS_OUTPUT.PUT_LINE(v_FirstName);
END;
3.4. record组合类型(相当于C中的结构体)
Example 1:
Type class is record(
Id students.id%type;
Name students.name%type;
Age studnets.age%type;
);
Sd0510 class;
Begin
Select * into sd0510 from classes where class_name=’sd0510’;
Dbms_output.put_line(sd0510.id);
End;
Example 2:
Declare
Type emp_type is record(
Emp_id s_emp.id%type,
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 36 页
Emp_first_name s_emp.first_name%type,
Emp_last_name s_emp.last_name%type
)
Emp emp_type;
Begin
Select * into emp from s_emp where id=1;
Dbms_output.put_line(emp.emp_id);
End;
3.5. Rowtype类型
Example 1:
declare
Emp s_emp%rowtype;
Begin
Select * into emp from s_emp where id=1;
End;
Table类型
Example 1:
Declare
Type t_emp is table of s_emp%rowtype index by binary_integer;
Emp t_emp;
Begin
Select * into emp(100) from s_emp where id = 100;
dbms_output.put_line('id===>'||emp(100).id);
dbms_output.put_line('first_name===>'||emp(100).first_name);
dbms_output.put_line('last_name===>'||emp(100).last_name);
end;
3.6. TABLE类型
TYPE Info IS TABLE OF S_EMP%ROWTYPE INDEX BY BINARY_INTEGER;
v_info Info;
3.7. 变量的作用域与可见性
如同JAVA
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 37 页
3.8. 控制语句
IF 判断语句
JAVA
If(logic expression){}
Else if(logic expression){}
Else{}
PL/SQL
If logic expression then ….
Elsif logic expression then
Endif
Example 1:
declare
i number;
begin
select count(*) into i from s_emp;
if i=0 then
dbms_output.put_line('no elements in s_emp');
elsif i<10 then
dbms_output.put_line('number < 10');
else
dbms_output.put_line(i);
end if;
end;
Loop 表达式
Loop
If logic_expression then exit;
End loop;
While表达式
While logic

End loop;
For 表达式(与JAVA的特点是)
For j in low..high loop
….
End loop;
GOTO语句
特点:只能从内部跳到外部
NULL语句
解决一些空语句的问题
Example 1:
If … then

Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 38 页
Else
Null;
End if;
Example 2:
If … then

Goto goto_end;
End;
<<goto_end>>
End;
3.9. SQL in PL/SQL
Data Manipulation language
Data Definition language
Transation Control
System comment
ESQL
在PL/SQL只能使用DML,Transation Control
3.10. Cursor 的使用
声明 Cursor s is select * from s_emp;
打开 Open s;
提取数据 FETCH S INTO emp;
EXIT WHEN S%NOTFOUND;
Cursor的关键字
Found
Notfound
Isopen
Rowcount
在loop中使用cursor
declare
cursor emp_cur is select * from s_emp;
emp s_emp%rowtype;
begin
loop
fetch emp_cur into emp;
if emp_cur%notfound then
exit;
end if;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 39 页
end loop;
close emp_cur;
end;
/
在while中使用cursor
Open emp_cur;
While emp_cur%found loop
Fetch emp_cur into emp;
Dbms_output.put_line(emp.id);
End loop;
Close emp_cur;
在for中使用cursor
open emp_cur;
for emp in emp_cur loop
dbms_output.put_line(emp.id);
end loop;
close emp_cur;
3.11. 异常的使用
异常分为:
系统异常
Dup_val_on_index
Timeout_on_resource
……
自定义异常
Example 1:
DECLARE
myException EXCEPTION;
F_NAME S_EMP.FIRST_NAME%TYPE;
F1_NAME S_EMP.FIRST_NAME%TYPE;
CURSOR S IS SELECT FIRST_NAME FROM S_EMP;
BEGIN
OPEN S;
LOOP
FETCH S INTO F_NAME;
EXIT WHEN S%NOTFOUND;
IF F_NAME IS NULL THEN
RAISE myException;
ELSE
DBMS_OUTPUT.PUT_LINE(' F_Name : ' || F_NAME);
END IF;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 40 页
END LOOP;
CLOSE S;
select first_name into f1_name from s_emp;
DBMS_OUTPUT.PUT_LINE(' F1_Name : ' || F1_NAME);
EXCEPTION
WHEN myException THEN
DBMS_OUTPUT.PUT_LINE(' Captured !');
CLOSE S;
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(' Captured NO DATA FOUND!');
END;
注意:for emp in emp_cur loop …..end loop;自动关闭cursor
3.12. 使用PROCEDURE
行参模式分为 in , out , int out 默认为 in
CREATE OR REPLACE PROCEDURE ModeTest(
p_In IN NUMBER,
p_Out OUT NUMBER,
p_inout IN OUT NUMBER)
IS
v_Local Number;
BEGIN
v_Local := p_In;
p_Out := 7;
p_InOut := 7;
END ModeTest;
/
注意: 如果在SQLPLUS里看详细的信息,show errors
In模式形参可以有默认值 DEFAULT 或者 :=
两种命名方法
名字标识法:
Test_procedure(outPara=>a,intPara=>b,inoutPara=>c);
outPara , intPara , inoutPara 为行参名字
位置标识法:
Test_procedure(a,b,c);
注意:要想直接在sqlplus运行procedure
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 41 页
Variable a number;
Variable b number;
Exec test_procedure(inpara=>100,outpara=>2);
输出结果
Print
以上命令只能用在SQLPLUS的CONSOLE
匿名块每次都编译,有名块第一次编译,以后不用。
删除PROCEDURE : drop procedure_name
3.13. 使用FUNCTION
3.13.1. 程序分两种:
1.通过create or replace 编译的存在数据库里
2.没有 create or replace 不存在数据库里
且只能被调用的父过程调用。
CREATE OR REPLACE FUNCTION lessthen_test(
src IN NUMBER,
ref IN NUMBER := 400)
RETURN BOOLEAN AS
BEGIN
IF src > ref THEN RETURN FALSE;
ELSE RETURN TRUE;
END IF;
END;
3.14. PACKAGE
3.14.1. 包的声明
CREATE OR REPLACE PACKAGE MyPackages IS
PROCEDURE AddStudent(
p_ID IN S_EMP.ID%TYPE,
p_FNAME IN S_EMP.FIRST_NAME%TYPE := '',
p_LNAME IN S_EMP.LAST_NAME%TYPE DEFAULT ''
);
FUNCTION DeleteStudent(
p_ID IN S_EMP.ID%TYPE
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 42 页
) RETURN BOOLEAN;
END MyPackages;
3.14.2. 包的定义
CREATE OR REPLACE PACKAGE BODY MyPackages AS
PROCEDURE AddStudent(
p_ID IN S_EMP.ID%TYPE,
p_FNAME IN S_EMP.FIRST_NAME%TYPE := '',
p_LNAME IN S_EMP.LAST_NAME%TYPE DEFAULT ''
) IS
Duplicate EXCEPTION;
i NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO i FROM S_EMP WHERE ID = p_ID AND FIRST_NAME = p_FNAME AND LAST_NAME = p_LNAME;
IF i = 0 THEN
INSERT INTO S_EMP (ID,FIRST_NAME,LAST_NAME) VALUES(p_ID,p_FNAME,p_LNAME);
COMMIT;
ELSE
RAISE Duplicate;
END IF;
EXCEPTION
WHEN Duplicate THEN
DBMS_OUTPUT.PUT_LINE('Duplicate Record');
END AddStudent;
FUNCTION DeleteStudent(
p_ID IN S_EMP.ID%TYPE
) RETURN BOOLEAN IS
i NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO i FROM S_EMP WHERE ID = p_ID;
IF i > 0 THEN
DELETE FROM S_EMP WHERE ID = p_ID;
COMMIT;
ELSE
NULL;
END IF;
RETURN TRUE;
END DeleteStudent;
Author: XuBin , MuDi Email: XuBin@tarena.com.cn , Mudi@tarena.com.cn 第 43 页
END;
3.14.3. 包的初始化代码
3.15. 触发器
CREATE OR REPLACE TRIGGER qiuTrigger after DELETE OR INSERT OR UPDATE ON S_EMP
FOR EACH ROW(行触发器,不写为语句触发器)
DECLARE
i NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO i FROM S_EMP
DBMS_OUTPUT.PUT_LINE(' Only ' || i || ' Student(s) left.');
END;
三种触发条件
两种触发时间
两种触发规则 (每行或每语句)
不能有事务语句
不能在正在修改的表
不可以修改任何变化表(定义触发器的表);
3.16. Pl/sql中执行动态SQL DDL语句
Execute immediate test_sql ;
使用占位符合
(:1)
Using id;
* clear screem

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值