oracle基础知识过一遍(原创)

用户、角色、权限、表空间

create tablespace test1_tablespace datafile ‘test1file.dbf’ size 10m;

create temporary tablespace temptest1_tablespace tempfile ‘temp1file.dbf’ size 10m;

创建永久表空间和临时表空间,并指定表空间名字,指定文件名称,大小(如不指定位置即放在默认位置)

select file_name from dba_data_files where tablespace_name=’test1_tablespace’;

select file_name from dba_temp_files where tablespace_name=’temptest1_tablespace’;

查看上面刚创建的永久表空间和临时表空间的文件所在位置dba_data_filesdba_temp_files

connect sys/oracle@orcl as sysdba  链接使用系统管理用户sys密码oracle,并以sysdba身份链接实例orclsysdba数据库管理员权限,sysoper数据库操作员权限,另外不写实例的话会链接默认实例)

create user yan identified by test default tablespace test1_tablespace temporary tablespace temptest1_tablespace;

创建用户yan密码test,设置默认表空间test1_tablespace、临时表空间temptest1_tablespace

select username from dba_users;  dba_users表中查询username

grant connect to yan;   授权connect操作给用户yan

connect yan/test   链接使用用户yan密码test

alter user yan identified by test123;   修改yan用户密码为test123

alter user yan account lock;  锁定用户yan(解锁就是unlock,当然要切换到有权限的用户下去执行此类命令)

drop user yan cascade;  删除用户yan及其创建的数据cascade参数是连同其创建的东西全部删除)

CONNECT(连接角色) 只可以登录ORACLE,不可以创建实体,不可以创建数据库结构

RESOURCE(资源角色) 可以创建实体,不可以创建数据库结构

DBA(数据库管理员角色) 拥有全部权限,最高权限,只有DBA才可以创建数据库结构

grant connect to user01;

grant resource to user01;

grant dba to user01;

创建自定义的角色

create role 角色名;

例子:create role manager;

赋予权限、回收权限

grant 权限 to 角色或用户   (grant A to B

例子:grant create table,create view to manager;   创建表、创建视图权限给角色manager

           grant manager to user01,user02;  角色manager赋予给用户user01user02

revoke 权限或角色 from 角色或用户   (grant A from B

例子:revoke manager from user01;  回收用户user01的角色manager权限

          revoke create table,create sequence from manager;  回收角色manager的创建表、创建序列权限

select * from system_privilege_map

create session 创建会话 create sequence 创建序列 create table 创建表 create user 创建用户 alter user 更改用户drop user 删除用户 create view 创建视图

授权对象权限、回收对象权限

对象权限有selectupdateinsertdeleteall......

grant 对象权限 on 对象 to 用户或角色   (如对象on user01.school

revoke 对象权限 on 对象 from 用户或角色  (如对象on user01.work

数据字典 dba_tablespaceuser_tablespace

select tablespace_name from dba_tablespace;

select tablespace_name from user_tablespace;     

数据字典 dba_usersuser_users

select default_tablespace,temporary_tablespace from dba_users where username=’system’

alter user 用户名 default tablespacetemporary tablespace 表空间名

alter user user01 default tablespace test1_tablespace temporary tablespace temptest1_tablespace

修改表空间状态

alter tablespace 表空间名 onlineofflineread onlyread write

修改表空间数据文件

alter tablespace 表空间名 add datafile’filename.dbf’ size 10M;  此为增加数据文件

alter tablespace 表空间名 drop datafile’filename.dbf’;  此为删除数据文件(不能删除第一个创建的数据文件,除非删除整个表空间)

删除表空间

drop tablespace 表空间名 (只删除表空间,不删除对应数据文件)

drop tablespace 表空间名 including contents (删除表空间及对应数据文件) 

表管理

DDL  数据定义语言

DML  数据操作语言

DCL  数据控制语言

TCL  事务控制语言

DDL常用语句:

create table 创建表 create index 创建索引 drop table 删除表 drop index 删除索引 truncate 删除表所有行 alter table 更改表结构,增加、修改、删除列 alter table add constraint 在已有表中增加约束

DML常用语句:

insert 添加数据 update 修改数据 delete 删除数据 select 查询数据

DCL常用语句:

grant 授予权限 revoke 撤销权限 lock 锁定

TCL常用语句:

commit 提交事务 rollback 回退事务 savepoint 设置保存点

创建表语法结构:

create table 表名 ( 列名 列数据类型 ,  列名 列数据类型 ... ...);

数据类型:字符类型、数值类型、日期时间类型、LOB类型

字符类型有 charvarchar2

数值类型 number[(p[,s])]   p表示精度,s表示小数点位数

number(5,0)最多可存储5位数整数  number(5,2)最大可存储999.99的浮点数

日期类型有 date

LOB类型有CLOBBLOB

例子:create table student( sid number(8,0),name varchar2(20),sex char(2),birthday date,address varchar2(50) );

约束是oracle提供的自动保持数据完整性的一种方法,它通过限制字段中的数据、记录中数据和表之间的数据来保证数据的完整性。

约束语法结构:[constraint 约束名] <约束类型>

主键约束、唯一性约束、默认约束、非空约束、检查约束、外部键约束

主键约束 primary key 它是唯一确定表中每一条记录的标识符,其值不能为NULL,也不能重复。表中主键只能有一个,但可以由多个列组成。

create table student(

sid number(8,0),

name varchar2(20),

sex char(2),

birthday date,

address varchar2(50),

constraint sid_pk primary key(sid) );

修改表添加主键约束

alter table student add constraint sid_pk primary key(sid);

非空约束用于确保列不能为NULL,它是列级约束。

列级约束:column [CONSTRAINT constraint_name] constraint_type 列级约束必须跟在列的定义后面

表级约束:column,… …

          [CONSTRAINT constraint_name] constraint_type

          (column,… …),                                   表级约束不与列一起,而是单独定义的

create table student(

sid number(8,0),

name varchar2(20) not null,  列级约束

sex char(2) constraint nn_sex not null,  列级约束

birthday date,

address varchar2(50),

constraint sid_pk primary key(sid) );  表级约束

修改表添加约束格式:

ALTER TABLE table_name ADD [CONSTRAINT constraint_name] constraint_type (column);

而非空约束要使用MODIFY语句 ALTER TABLE table_name MODIFY (column datatype NOT NULL);

删除约束方式可以禁用或者彻底删除

DISABLE|ENABLE CONSTRAINT constraint_name;

DROP CONSTRAINT constraint_name;

DROP PRIMARY KEY  为何这个可以这样写,因为表中只有一个呀,写不写约束名都知道的

ALTER TABLE table_name MODIFY column_name datatype NULL;

唯一约束用于指定一个或者多个列的组合值具有唯一性,以防止在列中输入重复值。

create table student(

sid number(8,0) unique, 列级约束

name varchar2(20),

sex char(2),

birthday date,

address varchar2(50),

constraint uk_sid unique(sid)); 表级约束

修改表添加唯一约束 alter table student add constraint uk_sid unique(sid);

检查约束对输入列或者整个表中的值设置检查条件,以限制输入值,保证数据完整性。

create table student(

sid number(8,0),

name varchar2(20),

sex char(2) check(sex=’男’ or sex=’女’),  列级约束

birthday date,

address varchar2(50),

constraint sid_pk primary key(sid) );

create table student(

sid number(8,0),

name varchar2(20),

sex char(2),

birthday date,

address varchar2(50),

constraint ck_sex check(sex=’男’ or sex=’女’));  表级约束

修改表添加检查约束 alter table student add constraint ck_sex check(sex=’男’ or sex=’女’);

外键约束是用于建立和加强两个表数据之间的链接的一列或多列。它是唯一涉及两个表关系的约束

列级约束:

CREATE TABLE 从表

(column_name datatype REFERENCES

主表(column_name) [ON DELETE CASCADE],… …);

表级约束:

CONSTRAINT constraint_name FOREIGN KEY (column_name)

REFERENCES 主表(column_name) [ON DELETE CASCADE]

设置外键约束时主表的字段必须是主键列(或唯一列),主从表中相应字段必须是同一数据类型,从表中外键字段的值必须来自主表中的相应字段的值(或为NULL

例子:

主表 create table department ( depid varchar2(10) primary key, depname varchar2(30) );

从表 create table student (sid number(8,0), name varchar2(20), sex char(2), birthday date, address varchar2(50),

        depid varchar2(10) references department(depid) );       列级约束,其中从表列名称可以和主表名称不一样

主表 create table department ( depid varchar2(10) primary key, depname varchar2(30) );

从表 create table student (sid number(8,0), name varchar2(20), sex char(2), birthday date, address varchar2(50),depid varchar2(10), constraint fk_depid foreign key(depid)              references department(depid) on delete cascade );       表级约束,同样从表定义的列可以和主表名称不一样

添加列语句结构:

ALTER TABLE 表名 ADD 新增列名 数据类型

ALTER TABLE student ADD tel varchar2(11)

修改列语句结构:

ALTER TABLE 表名 MODIFY 列名 新数据类型

ALTER TABLE student MODIFY tel number(11,0)

修改列名语句结构:

ALTER TABLE  表名 RENAME COLUMN  列名 TO 新列名

ALTER TABLE student RENAME COLNMN sex TO gender

删除表语句

TRUNCATE TABLE 表名 (用于删除表全部数据,但表结构还在,这种删除方式也叫截断表)

DROP TABLE 表名  (删除表结构)

添加信息语句结构:

INSERT INTO 表名[(1,2,… …)] VALUES(1,2,… …)

INSERT INTO student (sid,name,sex) VALUES(18733,’周小仙’,’男’)

查询信息语句结构:

SELECT * column_name FROM 表名

SELECT * FROM student      SELECT sid,name,sex FROM student

修改信息语句结构:

UPDATE table SET column = value [WHERE condition]

UPDATE student SET tel = ‘15899999999’ WHERE sid = 18733

删除信息语句结构:

DELETE FROM table [WHERE condition]

DELETE FROM student WHERE sid = 18733

事务可以看作是由数据库的若干操作组成的一个单元,这些操作要么都完成,要么都取消,从而保证数据满足一致性的要求。

事务组成可以是一条或者多条DML,或一条DDL,或一条DCL

DML语句需要使用COMMIT提交事务或使用ROLLBACK回滚事务

DDLDCL是自动提交事务的

使用事务的原因主要是为保证数据的安全有效,这里需要提到“表锁” 

基本查询

语法格式:

SELECT * {[DISTINCT] column_name | expression [alias],… …} FROM table_name [WHERE condition]

其中expression指表达式,alias指列的别名,condition指查询条件

查询有特定列查询、全部列查询、排除重复行、日期列的查询、条件查询(过滤数据,涉及运算符使用、范围查询、模糊查询、空值判断、逻辑运算符使用等)查询结果排序

SELECT DISTINCT deptno,job FROM emp   排除重复数据

ALTER SESSION SET nls_language=’SIMPLIFIED CHINESE’  以简体中文显示日期

ALTER SESSION SET nls_date_format=’YYYY/MM/DD’  以特定格式显示日期

运算符优先级 + - * / 从左到右执行,乘除高于加减,括号内优先

NULL表示未知值,和其运算结果也为空(即NULL

另外列可以给予默认值,使用default

列的别名用于改变列的显示标题

列别名可以跟在列名的后面,也可以在二者之间加AS关键字

SELECT  empno  “雇员编号”,  ename  “雇员名”,  sal*12  “全年工资” FROM emp

SELECT  empno AS “雇员编号”,  ename AS “雇员名”,  sal*12 AS “全年工资” FROM emp

连接符 ||

它把列与列,列与字符 连接在一起

Select ename ||’的岗位是:’|| job as 员工的职位信息描述 from emp

WHERE子句过滤条件

select * from emp where deptno=20

select * from emp where job=’manager’

select * from emp where hiredate=’22-3月-86

范围查询between…andin

模糊查询like               (通配符%表示0个或多个字符,通配符_表示单个字符)

判断空值is null

模糊查询中如果字符值本身就包含_%字符,就需要用escape选项和转义符实现

Select * from emp where ename like ‘G\_%’ escape ‘\’  其实模糊查询的是G_%

另外判断是否为空,不可以写成=NULL<>NULL 这都是错误写法,应该是is nullis not null

NOT优先级最高,AND其次,OR最低  

单列排序、多列排序、列别名排序

SELECT *|column_name FROM table_name [WHERE condition] [ORDER BY column_name [ASC|DESC] ]

SELECT语句包含多个子句(where,group by,having,order by)时,order by必须是最后一条语句

Select ename,sal from emp order by sal desc  降序排序

Select empno,ename,sal*12 年收入 from emp order by 年收入 desc  使用列别名排序

Select empno,ename,deptno,sal from emp order by deptno asc, sal desc  多列排序

单行函数

顾名思义就是输出一行的函数,当然多行函数就是输出一行或多行的函数

单行函数有字符函数、数值函数、日期函数、转换函数、通用函数

字符函数:1.大小写控制函数 有UPPERLOWERINITCAP

                  2.字符控制函数 有CONCATSUBSTRLENGTHINSTRLPADRPADTRIMREPLACE

UPPER(char) 用于将字符串转换为大写格式

LOWER(char) 用于将字符串转换为小写格式

INITCAP(char) 用于将字符串中的每个单词的首字母转换为大写格式,其他字符小写

CONCAT(str1,str2) 用于字符串的连接

例子concat(‘hello’,’oracle’)   结果:hellooracle

SUBSTR(char,m[n]) 用来截取字符串,char指定源字符串,m用于指定从哪个位置开始截取,n用于指定截取字符串的长度。如果m0,则从首字符开始,如果m为负数,则从尾部开始。

例子 substr(‘hello’,1,3)  结果:hel

例子 substr(‘hello’,0,3)  结果:hel

例子 substr(‘hello’,-1,1)  结果:o

LENGTH(char) 用于返回字符串的长度,字符串中的后缀空格也记作字符串的长度。

例子 length(‘oracle ‘)  结果:7

INSTR(char1,char2[,n[m]]) 用于指定字符串在源字符串中的位置,char1源字符串,char2指定字符串,n用于指定起始搜索位置,m用于指定字符串第m次出现的次数(n,m默认都是1

例子 instr(‘hello oracle’,’oracle’)  结果:7

例子 instr(‘hello oracle hello oracle’,’oracle’,2,2)  结果:20

LPAD(char1,n,char2) 用于在字符串的左端填充字符,char1源字符串,char2被填充字符,n用于指定填充后的char1的总长度。

例子 lpad(‘hello’,10,’#’)  结果:#####hello

RPAD(char1,n,char2) 用于在字符串的右端填充字符,char1源字符串,char2被填充字符,n用于指定填充后的char1的总长度。

例子 rpad(‘hello’,10,’@’)  结果:hello@@@@@

REPLACE(char,search_string[,replacement_string]) 用于替换字符串的子串内容,char源字符串,search_string被替换子串,replacement_string替换子串

例子 replace(‘hello oracle’,’oracle’,’world’)  结果:hello world

数值函数有ROUND、TRUNC、MOD

ROUND(n,[m]) 用于四舍五入结果,n可以是任意数字,m必须是整数

例子 round(25.328,2) 结果:25.33     round(25.328,-1) 结果:30

TRUNC(n,[m]) 用于截取数字,n可以是任意数字,m必须是整数

例子 trunc(25.328,2) 结果:25.32      trunc(25.328,-1) 结果:20

MOD(m,n) 用于求余数,m除于n得到的余数,如果n0,则返回结果为m

例子 mod(25,6) 结果:1     mod(25,0) 结果:25

日期函数常用函数有SYSDATE、MONTHS_BETWEEN、ADD_MONTHS、NEXT_DAY、LAST_DAY、ROUND、TRUNC

SYSDATE 用于返回当前系统日期

例子 select sysdate from dual

MONTHS_BETWEEN(d1,d2) 用于返回日期d1d2之间相差的月数。d1大于d2结果为正数,否则为负数

例子 select months_between(sysdate,hiredate) from emp

ADD_MONTHS(d,n) 用于返回特定日期时间之后或之前的月份所对应的日期时间。(求出若干月之后的日期)d用于指定日期时间,n可以是任意整数。

例子 select ename,add_months(hiredate,30*12) from emp

NEXT_DAY(d,char) 用于返回特定日期之后的第一个工作日所对应的日期。D用于指定日期时间值,char用于指定工作日。注意:当使用该函数时,工作日必须与日期语言匹配,假如日期语言为AMERICAN,那么周一对应于MONDAY;假如日期语言为简体中文,那么周一对应于”星期一”。

例子 select sysdate,next_day(sysdate,’星期一’) from dual

ROUND(d,[fmt]) 用于返回日期时间的四舍五入的结果。d用于指定日期的时间值,fmt用于指定四舍五入的方式,如果设置fmtYEAR,71日为分界线,如果设置fmtMONTH,16日为分界线。

例子 如果系统时间是’20-7-17’ round(sysdate,’YEAR’) 结果:01-1-18 round(sysdate,’MONTH’) 结果:01-8-17

TRUNC(d,[fmt]) 用于截断日期时间数据。d用于指定日期的时间值,fmt用于指定截断日期时间数据的方法,如果设置fmtYEAR,则结果为本年度的11日,如果设置fmtMONTH,则结果为本月1日。

例子 trunk(sysdate,’YEAR’)    trunk(sysdate,’MONTH’)

转换函数 TO_DATETO_CHARTO_NUMBER

TO_CHAR(d,[fmt[‘nlsparams’]]) 将日期类型转换为字符类型。d用于指定日期值,fmt用于指定日期格式模型,‘nlsparams’用于指定日期显示语言

例子 select to_char(hiredate,’DD-MON-RR’, ‘NLS_DATE_LANGUAGE=AMERICAN’) from emp

TO_CHAR(n,[fmt]) 将数值类型转换为字符类型。n用于指定数值,fmt用于指定数字格式模型。

格式模型,常见的元素如下:

9:显示数字,并且会忽略前导0

0:显示数字,如果位数不足,则用0补齐

. :在指定位置显示小数点

, :在指定位置显示逗号

$ :在数字前加美元符号

L :在数字前加本地货币符号

例子 select sal,to_char(sal,’L999,999.99’) from emp  select sal,to_char(sal,’$999.999.99’) from emp

TO_DATE(char,[fmt[‘nlsparams’]]) 将字符串转换成日期类型的数据。Char用于匹配日期数据的字符串,fmt用于指定日期格式模型,’nlsparams’用于指定日期语言。

例子 select ename,hiredate from emp where hiredate>to_date(‘1986-3-22’,’YYYY-MM-DD’)

TO_NUMBER(n,[fmt]) 将包含数字的字符串转换成数值类型。N是包含数字的字符串,fmt用于指定数字格式模型

例子 select ename,sal from emp where sal>to_number(‘2000’,’L99999’)

通用函数有NVLNVL2NULLIFCOALESCE

NVL(expr1,expr2) 该函数用于处理NULL,如果expr1null,则返回expr2,如果expr1不是null,则返回expr1

例子 select ename,sal,comm,sal+nvl(comm,0) from emp

NVL2(expr1,expr2,expr3) 该函数用于处理NULL,如果expr1不是null,则返回expr2,如果expr1null,则返回expr3

例子 select ename,sal,comm,nvl2(comm,sal+comm,sal) from emp

NULLIF(expr1,expr2) 该函数用于比较表达式expr1expr2,如果二者相等,则返回NULL,否则返回expr1

例子 select empno,ename,hiredate,nullif(hiredate,trunk(sysdate,’MONTH’)) from emp

COALESCE(expr1,[expr2]… ) 用于返回表达式列表中的第一个NOT NULL表达式的结果

例子 select ename,sal,comm,coalesce(sal+comm,sal) from emp

CASE表达式语法格式

CASE expr

     WHEN comparison_expr1 THEN return_expr1

     [WHEN comparison_expr2 THEN return_expr2

     … …

     ELSE else_expr]

END

例子 select empno,ename,

          case job

          when ‘CLERK’ then ‘办事员’

          when ‘SALESMAN’ then ‘销售’

          else ‘总裁’

          end

     from emp

DECODE(column | expression,search1,result1,[ search2,result2,  …] [default])

例子 select empno,ename,job,decode(job, ‘CLERK’, ‘办事员’, ‘SALESMAN’ , ‘销售’, ‘总裁’) from emp

单行函数看可以嵌套。嵌套函数的执行顺序是由内到外。

例子 to_char(next_day(add_months(hiredate,3),’星期一’),’YYYY-MM-DD’)

       to_char(round(sal/30,2),’L999,999’)

分组函数

分组函数有avgsumminmaxcountwm_concat

分组函数就是多行函数,作用于一组数据,并一组数据返回一个值。

Select avg(sal) from emp

Select min(sal) from emp

Select max(sal) from emp

Select count(*) from emp

Distinct关键字去除重复记录 select count(distinct deptno) from emp

WM_COUCAT行转列(让查询结果行转列)该函数可以把列值以 逗号 分隔起来,并显示成一行。

Select wm_concat(ename) from emp

使用分组函数要注意空值的问题,分组函数会自动忽略空值,如果要空值的数据,可以用NVL函数

数据分组 GROUP BY

select列表中的所有未包含在组函数中的列都应包含在group by子句中

正确写法:select deptno,avg(sal) from emp group by deptno

错误写法:select deptno,avg(sal) from emp

错误写法:select deptno,job,avg(sal) from emp group by deptno

正确写法:select deptno,job,avg(sal) from emp group by deptno,job

包含在group by子句中的列不必包含在select列表中

Select avg(sal) from emp group by deptno

Having子句 用于对分组后的结果进行过滤

Select deptno,avg(sal) from emp group by deptno having avg(sal)>2500  这里的having不能换成where

不能在where子句中使用组函数,可以在having子句中使用组函数。

分组函数嵌套时候需要配合group by子句一起使用

例子 select * max(avg(sal)) from emp group by deptno  如果没有group by子句会报错的

多表查询和笛卡尔集

多表查询顾名思义就是从多个表中获取数据

笛卡尔集是集合的一种,它是数学上的概念。假设AB都是集合,AB的笛卡尔积用A*B来表示,那么A*B所形成的集合叫笛卡尔集。

Oracle多表查询

等值连接,它是指使用等值比较符 = 指定连接条件的查询

例子 select empno,ename,job,dname from emp,dept where emp.deptno=dept.deptno

例子 用表别名方式 select e.empno,e.ename,e.job,d.dname from emp e,dept d where e.deptno=d.deptno

在连接查询中,当有多个连接条件时,使用AND指定其他条件

例子 select e.empno,e.ename,e.job,d.dname from emp e,dept d where e.deptno=d.deptno and e.deptno=10

不等值连接,它是指使用除等值比较符之外的其他比较操作符执行连接查询

例子 select e.empno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between losal and hisal

外连接是标准连接的拓展,它不仅会返回满足连接条件的所有记录,而且还会返回不满足连接条件的部分记录

外连接是用+操作符来完成的,分右外连接、左外连接

右外连接:SELECT table1.column, table2.column FROM table1,table2 WHERE table1.column(+)=table2.column

返回右边表table2的全部记录,包括不满足条件的记录。返回左边table1满足条件的记录。

左外连接:SELECT table1.column, table2.column FROM table1,table2 WHERE table1.column=table2.column(+)

返回左边表table1的全部记录,包括不满足条件的记录。返回右边table2满足条件的记录。

例子 select d.deptno,d.dname,count(e.empno) from dept d,emp e where d.deptno=e.deptno(+) group by d.deptno,d.dname

自连接是同一张的互相连接,实质是将同一张表看成是多张表

SQL:1999标准

SELECT table1.column_name, table2.column_name FROM table1

[CROSS JOIN table2]|[NATURAL JOIN table2]|[JOIN table2 USING (column_name)]|

[JOIN table2 ON (table1.column_name= table2.column_name)]|

[LEFT | RIGHT | FULL OUTER JOIN table2 ON (table1.column_name= table2.column_name)]

交叉连接

例子 select e.detpno,e.ename,d.deptno,d.dname from emp e cross join dept d

自然连接是一种特殊的等价连接,它将表中具有相同名称的列自动进行记录匹配。自然连接不必指定任何同等连接条件

例子 select table1.column_name,table2.column_name from table1 natural join table2

内连接,返回两个表中想匹配的数据(只返回满足条件的数据)

等值连接、非等值连接、自然连接都属于内连接

USING子句建立相等连接

例子 select e.ename,e.sal,d.dname from dept d join emp e using(deptno)  两个表都有的列deptno

ON子句建立相等连接

例子 select e.ename,e.sal,d.dname from dept d join emp e on e.deptno=d.deptno

左外连接、右外连接、完全外连接

例子 select e.ename,e.sal,d.dname from dept d left join emp e on e.deptno=d.deptno

例子 select e.ename,e.sal,d.dname from dept d right join emp e on e.deptno=d.deptno

例子 select e.ename,e.sal,d.dname from dept d full join emp e on e.deptno=d.deptno

Set运算符,并不是set这个符号,它是集合操作符,专门用于合并多条SELECT语句的结果。

union/union all 并集  intersect 交集  minus 差集

例子 select deptno,empno,ename from emp1

        union

        select deptno,empno,ename from emp2

union allunion不同的是它不会取消重复行,并且不会对结果集数据进行排序

例子 select deptno,empno,ename from emp1

        union all

        select deptno,empno,ename from emp2

例子 select deptno,empno,ename from emp1

        intersect

        select deptno,empno,ename from emp2

例子 select deptno,empno,ename from emp1

        minus

        select deptno,empno,ename from emp2

子查询

子查询是指嵌套在其他SQL语句中的SELECT语句,也称为嵌套查询。

例子 select * from emp where job=(select job from emp where ename=’SMITH’)

一个主查询可以有多个子查询

例子 select * from emp where job=(select job from emp where empno=7521)

                and sal>(select sal from emp where empno=7934)

执行顺序,一般是先执行子查询,再执行主查询,但相关子查询例外

什么是相关子查询?

当子查询需要引用主查询到的表列时,ORACLE会执行相关子查询,也就是先执行主查询,再执行子查询。

例子 select ename,sal,deptno from emp e where sal>(select avg(sal) from emp where deptno=e.deptno)

主查询和子查询可以不是同一张表

单行子查询和多行子查询,这个自己去体会,其实就是返回的是单行还是多行,另外知道它们各自的运算符。

子查询需注意的问题:

  1. 不可以在group by子句中使用子查询
  2. TOP-N分析问题中,须对子查询排序
  3. 单行子查询和多行子查询中的空值问题

视图

视图是一个虚拟的表,它是建立在已有表的基础上的,视图赖以建立的这些表称为基表。

使用视图主要原因:1.安全原因,限制数据访问 2.视图可使复杂的查询易于理解和使用

视图分:简单视图、复杂视图、连接视图、只读视图

创建视图语法格式:

CREATE [OR REPLACE] VIEW view_name [(alias[,alias]…)]                           alias是视图列的别名

      AS subquery

      [WITH CHECK OPTION [CONSTRAINT constraint]] [WITH READ ONLY]

简单视图例子 create view emp_view as select empno,ename,sal from emp

连接视图例子 create view dept_view as select d.deptno,d.dname,e.empno,e.ename,e.job

                                  From dept d,emp e

                                  Where d.deptno=e.deptno and d.deptno=10

只读视图例子 select view emp_view as select * from emp where deptno=10 with read only

视图DML操作

Select * from emp_view

Insert into emp_view(empno,ename,sal)values(888.’LAYAN’,666)

Update emp_view set sal=sal+100 where empno=888

Delete from emp_view where empno=888

针对视图的更新操作(insertupdatedelete)实际改变的是基表中的数据

视图定义CHECK约束

create view emp_view as select * emp where deptno=20 with check option constraint chk_view

以上代码,如果去更新插入或删除不是deptno=20的信息,会报错提示违反了约束

修改视图例子 create or replace view emp_view as select * from emp where job=’SALSMAN’

删除视图例子 drop view emp_view  (只是删除视图的定义,并没有删除基表中的数据)

复杂视图是指包括函数、表达式或分组数据的视图,它主要用于执行查询操作。

注意当定义复杂视图时,必须要为函数或表达式定义列别名。

例子 create view job_view(job,avgsal,sumsal,maxsal,minsal)

         As

         select job,avg(sal),sum(sal),max(sal),min(sal) from emp  group by job

复杂视图执行DML操作原则:

    视图中包含以下元素之一不能执行delete操作:

  1. group by子句
  2. 分组函数
  3. distinct关键字
  4. rownum伪列

    视图中包含以下元素之一不能执行update操作:

  1. group by子句
  2. 分组函数
  3. distinct关键字
  4. rownum伪列
  5. 使用表达式定义的列

    视图中包含以下元素之一不能执行insert操作:

  1. group by子句
  2. 分组函数
  3. distinct关键字
  4. rownum伪列
  5. 使用表达式定义的列
  6. 视图上没有包含基表的not null

序列、索引、同义词

创建序列语法格式:

CREATE SEQUENCE sequence_name

       [INCREMENT BY n]  每次增长的数值(步长)

       [START WITH n]  从哪个值开始(初始值)

       [{MAXVALUE n|NOMAXVALUE}]

       [{MINVALUE n|NOMINVALUE}]

       [{CYCLE|NOCYCLE}]  是否需要循环

       [{CACHE n|NOCACHE}]  是否缓存

当使用序列时,必须通过伪列nextvalcurrval来引用序列。

例子 deptno_seq.nextval  引用返回下一个序列值

例子 deptno_seq.currval   引用返回当前序列值

查询数据字典视图 USER_SEQUENCES获取序列定义信息

SELECT sequence_name,min_value,max_value,increment_by,cycle_flag,cache_size,last_number FROM user_sequences

注意在定义cache,可提高访问效率,但使用时在:回滚、系统异常、多个表同时使用同一序列等情况下出现跳号

修改序列语法格式:

ALTER SEQUENCE sequence_name

       [INCREMENT BY n]  每次增长的数值(步长)

       [{MAXVALUE n|NOMAXVALUE}]

       [{MINVALUE n|NOMINVALUE}]

       [{CYCLE|NOCYCLE}]  是否需要循环

       [{CACHE n|NOCACHE}]  是否缓存

注意序列的初始值不能修改

删除序列 DROP SEQUENCE sequence_name

索引是为了加速对表中数据行的检索而创建的一种存储结构。

按索引列的个数分类有:单列索引、复合索引

按索引列值的唯一性分类有:唯一索引、非唯一索引

在一个或多个列上创建索引

CREATE INDEX index_name ON table(column …)

单列索引例子 create index idx_ename on emp(ename)

复合索引例子 create index idx_deptno_job on emp(deptno,job)

唯一索引例子 create unique index idx_dname on dept(dname)      dname列值不可重复

非唯一索引例子 create index idx_job on emp(job)                 job列值可以重复

删除索引  drop index idx_dname

同义词是数据库方案对象的一个别名。

那什么是方案?方案对象比如表、索引、视图、触发器、序列、同义词、存储过程等

              非方案对象比如表空间、用户、角色等

同义词分公共同义词和私有同义词

公共同义词是指数据库中所有的用户都可以使用

私有同义词只能被创建它的用户所拥有,其他用户在引用时必须带有方案名

创建公共同义词 CREATE PUBLIC SYNONYM synoym FOR [schema.]object

创建私有同义词 CREATE SYNONYM synoym FOR [schema.]object

注:schema指方案名

例子 create public synonym dn for scott.deptnew  scott用户下的deptnew表创建其同义词dn

        select * from dn  就相当于查找scott用户下的deptnew

PL/SQL

PL/SQL是一种程序语言,叫做过程化SQL语言。它是ORACLE数据对SQL语言的扩展

PL/SQL是面向过程的语言,是对SQL语言的扩展

块,是PL/SQL的基本程序单元

PL/SQL块由三部分构成:声明部分、执行部分、异常处理部分

DECLARE       声明部分,声明变量、常量、复杂数据类型、游标等

BEGIN       执行部分,PL/SQL语句和SQL语句

EXCEPTION        异常处理部分,处理运行错误

END         块结束标记

打印输出hello everyone  

注意:当使用DBMS_OUPUT包输出信息时,需要设置SQL*Plus环境serveroutput的值为ON

set serveroutput on

BEGIN

dbms_output.put_line(‘hello everyone’)

END

PL/SQL块的分类:

匿名块:动态构造、只能执行一次。

子程序:存储在数据库中的存储过程、函数及包等。当在数据库上建立好后可以在其它程序中调用它们。

触发器:当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。

标识符

当编写PL/SQL块时,为了临时存储数据,需要定义变量和常量。那么变量和常量的定义是需要满足标识符的限制要求的:

  1. 标识符名不能超过30个字符
  2. 第一个字符必须为字母
  3. 不分大小写
  4. 不能用’-’(减号)

注意:尽量不把变量名声明和表中字段名一样。

建议遵从下面编码规则:

程序变量  v_name

程序常量  c_name

游标变量  name_curror

异常标识  e_name

记录类型  name_record

注释

单行注释: --注释内容                             多行注释:  /*注释内容*/

引用变量

在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据。在这种情况下,变量应该拥有与表列相同的类型。

想一想,当用某个变量在定义和应用时候对应某表列的数据类型,如果这个表列数据类型变了,你还得去修改对应的这个变量,如果涉及的地方很多,烦不烦?

例子  DECLARE

             v_name varchar2(10);

         BEGIN

             SELECT ename INTO v_name FROM emp WHERE empno=8888;

         END;

emp表的ename列数据类型如果改变,那么定义的变量v_name也要随着去改变

怎么才能让其变量自动随着其对应表列数据类型的改变而改变,这就是引用型变量、记录型变量的作用。

引用型变量是指其数据类型与已经定义的某个数据变量的类型相同,或者与数据库表的某个列的数据类型相同。

例子  v_name  emp.ename%TYPE

这样v_name就不关心其到底是什么数据类型,反正跟emp.ename一样,你变我也变。emp.ename也可以放心的改变其数据类型,不会影响v_name

记录型变量,PL/SQL提供%ROWTYPE操作符,返回一个记录类型,其数据类型和数据库表的数据结构相一致。

例子  emp_record  emp%ROWTYPE

这样emp_record对应emp表的数据结构,也就是说emp_record含有emp表所有的列,emp_record不必关心到底有多少个列,每个列是什么数据类型,反正跟emp表中的所有列一样,你变我也变。Emp表也可以放心改变,因为不会影响emp_record

记录型变量分量的引用   如:emp_record.ename:=’ROSE’ 

了解算术运算符、关系运算符、比较运算符、逻辑运算符

补充    := 是赋值意思  &n1 输入值,其中n1是自定名称

另外注意NULL1.空值+数字=空值    2.空值 || 字符串1 还等于字符串1

PL/SQL流程控制语句分类:

  1. 条件控制语句 IF条件语句和CASE条件 语句
  2. 循环语句 有基本循环LOOP语句、WHILE循环语句、FOR循环语句
  3. 顺序语句 GOTO语句和NULL语句

以上不做详细介绍,说下特别的部分

嵌套循环是指一个循环语句中嵌入另一个循环语句。

标号用于标记嵌套块或嵌套循环。

使用<<label_name>>定义标号

例子   DECLARE

            v_result  int

          BEGIN

            <<outter>>

            FOR i IN 1..5 LOOP

                <<inter>>

                FOR j IN 1..5 LOOP

                    v_result:=i;

                    EXIT outter WHEN i=4;

                END LOOP inter;

                DBMS_OUTPUT.PUT_LINE(‘||v_result);

            END LOOP outter;

            DBMS_OUTPUT.PUT_LINE(‘||v_result);

         END;

EXIT WHEN 是当满足某条件时跳出循环

CONTINUE WHEN 是当满足某条件时跳出当前循环,进入下一个循环

GOTO语句用于跳转到特定标号处执行语句   如:GOTO  lable_name   (标号lable_name要在某处标识好)

注意:当使用GOTO跳转到特定标号时,标号后至少要包含一条执行语句。

NULL语句不会执行任何操作,并且会直接将控制传递到下一个语句,使用该语句主要为了提高可读性。 

游标

游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。

游标的作用是用于临时存储从数据库中提取的数据块。

通俗来讲游标就是一个结果集。

游标类型分为:显示游标和隐式游标

显示游标处理的四个步骤:

定义游标

CURSOR cursor_name[(parameter_name datatype)] IS select_statement

打开游标

OPEN cursor_name

提取数据

FETCH cursor_name INTO variable1[,variable2,… ]

关闭游标

CLOSE cursor_name

查询所有员工的员工号、姓名和职位的信息

DECLARE

  --定义游标

  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp

  v_empno  emp.empno%TYPE

  v_ename  emp.ename%TYPE

  v_job     emp.job%TYPE

BEGIN

  --打开游标、执行查询

  OPEN emp_cursor

  --提取数据

  LOOP

FETCH emp_cursor INTO v_empno,v_ename,v_job

dbms_output.put_line(‘员工号:|| v_empno || ‘姓名: || v_ename || ‘职位: || v_job)

--当找不到数据的时候退出

EXIT WHEN emp_cursor%NOTFOUND

  END LOOP

  --关闭游标

  CLOSE emp_cursor

END

显示游标的属性

%FOUND 该属性用于检测游标结果集是否存在数据,如果存在数据,返回TRUE

%NOTFOUND 该属性用于检测游标结果集是否不存在数据,如果不存在数据,返回TRUE

%ISOPEN 该属性用于检测游标是否已经打开,如果已经打开返回TRUE

%ROWCOUNT 该属性用于返回已提取的实际行数

按职工的职称涨工资,总裁涨1000元,经理涨500元,其他员工涨300

DECLARE

  --定义游标

  CURSOR empnew_cursor IS SELECT empno,job FROM empnew

  v_empno  empnew.empno%TYPE

  v_job     empnew.job%TYPE

BEGIN

  --打开游标、执行查询

  OPEN empnew_cursor

  --提取数据

  LOOP

FETCH empnew_cursor INTO v_empno ,v_job

IF v_job=’president’ THEN

  UPDATE empnew SET sal=sal+1000 WHERE empnew=v_empno

ELSIF v_job=’manager’ THEN

  UPDATE empnew SET sal=sal+500 WHERE empnew=v_empno

ELSE

  UPDATE empnew SET sal=sal+300 WHERE empnew=v_empno

END IF

EXIT WHEN empnew_cursor%NOTFOUND

  END LOOP

  COMMIT

  --关闭游标

  CLOSE empnew_cursor

END

当使用游标FOR循环时,ORACLE会隐含地打开游标,提取数据并关闭游标

语法格式:

FOR record_name IN cursor_name LOOP

  Statement

END LOOP

查询所有员工的员工号、姓名和职位的信息

DECLARE

  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp

BEGIN

  FOR emp_record IN emp_cursor LOOP

    dbms_output.put_line(‘员工号:|| emp_record.empno || ‘姓名: || emp_record.ename || ‘职位: || emp_record.job)

  END LOOP

END

可以改进下

BEGIN

  FOR emp_record IN (SELECT empno,ename,job FROM emp) LOOP

    dbms_output.put_line(‘员工号:|| emp_record.empno || ‘姓名: || emp_record.ename || ‘职位: || emp_record.job)

  END LOOP

END

参数游标是指带有参数的游标。通过使用参数游标,使用不同参数值可以生成不同的游标结果集。

语法格式:

CURSOR cursor_name (parameter_name datatype) IS select_statement

OPEN cursor_name (parameter_value)

参数游标例子

DECLARE

  CURSOR emp_cursor(dno NUMBER) IS SELECT empno,ename,job FROM emp WHERE deptno=dno

BEGIN

  FOR emp_record IN emp_cursor(&no) LOOP

    dbms_output.put_line(‘员工号:|| emp_record.empno || ‘姓名: || emp_record.ename || ‘职位: || emp_record.job)

  END LOOP

END

显示游标是用户自定义的显示创建的游标,主要是用于对查询语句的处理。

隐式游标是由系统隐含创建的游标。主要用于对非查询语句,如修改,删除等操作,则有ORACLE系统自动地为这些操作设置游标并创建其工作区,对于隐式游标的操作,如定义、打开、取值及关闭操作,都有ORACLE系统自动完成,无需用户进行处理。

隐式游标的名字为SQL,这是由ORACLE系统定义的。

隐式游标DML操作和单行SELECT语句会使用隐式游标,它们是:

  插入操作 insert

  更新操作 update

  删除操作 delete

  单行查询操作 select…into

当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。

注意:通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。

隐式游标属性: SQL%FOUND  SQL%NOTFOUND  SQL%ISOPEN  SQL%ROWCOUNT

为了对正在处理(查询)的行不被另外的用户改动,oracle提供一个for update子句来对所选择的行进行锁住。

如果创建的游标需要执行更新或删除的操作必须带有for update子句

FOR UPDATE子句会将游标提取出来的数据进行行级锁定,这样在本会话更新期间,其他用户的会话就不能对当前游标中的数据行进行更新操作。

语法格式:

CURSOR cursor_name IS select_statement

FOR UPDATE [OF column_reference] [NOWAIT]

UPDATE table_name SET column=… WHERE CURRENT OF cursor_name

DELETE FROM table_name WHERE CURRENT OF cursor_name 

异常处理

异常处理是为了提高程序的健壮性,使用异常处理部分可以有效地解决程序正常执行过程中可能出现的各种错误,是程序正常运行。

异常处理语法格式:

EXCEPTION

  WHEN first_exception THEN

Statement1  …

  WHEN second_exception THEN

Statement2  …

  WHEN OTHERS THEN

Statement3  …

异常处理的分类:

  1. 预定义异常  2.非预定义异常  3.自定义异常

异常处理代码的PL/SQL块中的位置

DECLARE     声明部分—声明变量、常量、复杂数据类型、游标等

BEGIN       执行部分—PL/SQL语句

EXCEPTION   异常处理部分—处理运行错误

END         块结束标记

预定义异常是指有PL/SQL所提供的系统异常,oracle提供了20多个预定义异常,每个预定义异常对应一个特定的oracle错误,当PL/SQL块出现这些oracle错误时,会隐含地触发相应的预定义异常。

对于预定义异常情况的处理,无需在程序中定义,只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可。

例子:根据输入的工资,查询员工的姓名,并输出员工的姓名及工资

分析:1.输入工资,需要替代变量&salary

          2.根据工资查询员工的姓名,并将查询到的姓名赋值给姓名变量。数据库赋值需要用到SELECT…INTO

          3.考虑一些特殊情况,如没有该工资的员工,该工资有多个员工

DECLARE

  v_name  emp.ename%TYPE;

  v_sal    emp.sal%TYPE:=&salary;

BEGIN

  SELECT ename INTO v_name FROM emp WHERE sal=v_sal;

  DBMS_OUTPUT.PUT_LINE(v_name||’的工资是:’||v_sal);

EXCEPTION

  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;

非预定义异常用于处理预定义异常所不能处理的oracle错误,此种异常需要在程序中定义。

非预定义异常的处理包括3步:

1.PL/SQL块定义部分定义异常情况

  <异常情况>EXCEPTION;

2.将其定义好的异常情况与标准的oracle错误联系起来,使用PRAGMA EXCEPTION_INIT语句

  PRAGMA EXCEPTION_INIT(<异常情况><错误代码>);

3.PL/SQL块的异常情况处理部分对异常情况作出相应的处理。

例子 删除dept表中指定部门的信息

分析 deptemp表之间具有主外键关系,当删除指定部门的信息时,应确保该部门下没有员工。

     先获得其错误代码此处略

DECLARE

  --1.定义非预定义异常的标识符

  e_fk EXCEPTION;

  --2.oracle错误与异常建立关联

  PRAGMA EXCEPTION_INIT(e_fk,-2292);

BEGIN

  DELETE FROM dept WHERE deptno=&deptno;

EXCEPTION

  WHEN e_fk THEN

     --3.捕捉并处理异常

     DBMS_OUTPUT.PUT_LINE(‘此部门下有员工,不能删除);

  WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE(SQLCODE||’###’||SQLERRM);

END;

自定义异常

如果你想在某个特定事件发生时向应用程序的用户发出一些警告信息。而事件本身不会抛出oracle内部异常,这个异常是属于应用程序特定异常。那么就需要自定义异常。

用户定义的异常错误是通过显式使用RAISE语句来触发。当引发一个异常错误时,控制就转向到EXCEPTION块异常错误部分,执行错误处理代码。

自定义异常的处理步骤:

1.PL/SQL块的声明部分定义异常情况:

  <异常情况>EXCEPTION

2.RAISE<异常情况>

3.PL/SQL块的异常情况处理部分对异常情况做出相应的处理

DECLARE

  v_empno     emp.empno%TYPE:=&empno;

  e_no_result   EXCEPTION;

BEGIN

  UPDATE emp SET sal=sal+100 WHERE empno=v_empno;

  IF SQL%NOTFOUND THEN

    RAISE e_no_result;

  ELSE

    COMMIT;

  END IF;

EXCEPTION

  WHEN e_no_result THEN

    DBMS_OUTPUT.PUT_LINE(‘数据更新失败);

  WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(‘其他错误);

END;

异常处理函数

异常处理函数用于取得oracle错误号和错误信息,其中函数SQLCODE用于取得错误号,SQLERRM用于取得错误信息。当编写PL/SQL块时,通过在异常处理部分引用函数SQLCODESQLERRM,可以取得未预计到的oracle错误。另外,通过使用内置过程RAISE_APPLICATION_ERROR,可以在建立子程序(过程、函数、包)时自定义错误号和错误信息。

例子:

DECLARE

  v_empno    emp.empno%TYPE:=&empno;

  v_ename    emp.ename%TYPE:=’&ename’;

  v_deptpno   emp.deptpno%TYPE:=&deptpno;

BEGIN

  INSERT INTO emp(empno,ename,deptno) VALUES(v_empno, v_ename, v_deptpno);

  IF SQL%FOUND THEN

    DBMS_OUTPUT.PUT_LINE(‘数据插入成功);

    COMMIT;

  END IF;

EXCEPTION

  WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(‘错误号:||SQLCODE);

    DBMS_OUTPUT.PUT_LINE(‘错误信息:||SQLERRM);

END;

RAISE_APPLICATION_ERROR语法格式:

  raise_application_error(error_number,message);

  error_number用于定义错误号(-20000-20999)

  messag用于指定错误信息,长度不能超过2048个字节

例子:

CREATE OR REPLACE PROCEDURE change_sal (eno NUMBER,salary NUMBER)

IS

BEGIN

  UPDATE emp SET sal=salary WHERE empno=eno;

  IF SQL%NOTFOUND THEN

    RAISE_APPLICATION_ERROR(-20000,’该员工不存在);

  ELSE

    DBMS_OUTPUT.PUT_LINE(‘更新成功);

    COMMIT;

  END IF;

END;

存储过程与存储函数

创建存储过程的语法格式:

CREATE [OR REPLACE] PROCEDURE procedure_name

  [( argment1 [ {IN|OUT|IN OUT}] TYPE,

    argment2 [ {IN|OUT|IN OUT}] TYPE,…)]

  { IS|AS }

声明部分,类型、变量的说明

BEGIN

执行部分

EXCEPTION

可选的异常错误处理部分

END

例子:创建带有输入参数的存储过程(代码中没有COMMIT命令,存储一般是用来调用的,所以没有啦)

CREATE OR REPLACE PROCEDURE proc1

(v_empno IN empnew.empno%TYPE)

IS

BEGIN

  --根据员工号删除指定的员工信息

  DELETE FROM empnew WHERE empno=v_empno;

  --判断是否删除成功

  IF SQL%NOTFOUND THEN

    --错误号在-20000-20999之间

    RAISE_APPLICATION_ERROR(-20008,’指定删除的员工不存在’);

  ELSE

    DBMS_OUTPUT.PUT_LINE(‘删除成功’);

  END IF;

END;

例子:再创建带有输出参数的存储过程

CREATE OR REPLACE PROCEDURE proc2

(v_deptno IN NUMBER, v_avgsal OUT NUMBER, v_cnt OUT NUMBER)

IS

BEGIN

  SELECT AVG(sal),COUNT(*)

  INTO v_avgsal,v_cnt

  FROM emp

  WHERE deptno=v_deptno;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE(‘没有此部门);

    WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(SQLERRM);

END;

例子:创建带有输入输出的存储过程

CREATE OR REPLACE PROCEDURE proc3

(v_num1 IN OUT NUMBER, v_num2 IN OUT NUMBER)

AS

  v_temp NUMBER:=0;

BEGIN

  v_temp:=v_num1;

  v_num1:=v_num2;

  v_num2:=v_temp;

END;

创建存储过程的语法格式:

CREATE [OR REPLACE] FUNCTION procedure_name

  [( argment1 [ {IN|OUT|IN OUT}] TYPE, argment2 [ {IN|OUT|IN OUT}] TYPE,…)]

RETURE

  { IS|AS }

声明部分,类型、变量的说明

BEGIN

执行部分

RETURE

EXCEPTION

可选的异常错误处理部分

END

例子:根据您部门编号返回该部门的总工资

CREATE OR REPLACE FUNCTION func1

(v_deptno IN NUMBER)

RETURE NUMBER

IS

  v_sumsal NUMBER;

BEGIN

  SELECT SUM(sal) INTO v_sumsal FROM emp WHERE deptno=v_deptno;

  RETURE v_sumsal;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE(‘没有此部门);

    WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(SQLERRM);

END;

例子:根据员工号输出员工的姓名和工资,并返回员工的年收入

CREATE OR REPLACE FUNCTION func2

(v_empno IN emp.empno%TYPE, v_name OUT emp.ename%TYPE, v_sal OUT emp.sal%TYPE)

RETURE NUMBER

IS

  v_salsum NUMBER;

BEGIN

  SELECT ename,sal,(sal+nvl(comm,0))*12

 INTO v_name,v_sal,v_salnum

FROM emp

WHERE deptno=v_deptno;

  RETURE v_salsum;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE(‘没有此员工);

    WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(SQLERRM);

END;

例子:求两个数的平方,并输出两个数的平方和

CREATE OR REPLACE FUNCTION func3

(n1 IN OUT NUMBER, n2 IN OUT NUMBER)

RETURE NUMBER

AS

BEGIN

  n1:=n1*n1;

  n2:=n2*n2;

  RETURE n1+n2

END;

存储过程的调用

一种是使用EXECUTE语句来实现

EXECUTE procedure_name (parameter1, parameter2…)

另外一种就是在PL/SQL代码中直接调用

BEGIN

  procedure_name (parameter1, parameter2…)

END

删除存储过程

DROP PROCEDURE [user.]procedure_name

调用存储函数也调用存储过程一毛一样,不再啰嗦了,因为他们真的差不多,是否他们区别就在于是否有返回值?

包是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合。

它具有面向对象程序设计语言的特点,是对PL/SQL程序设计元素的封装,它使程序设计模块化。

包中的程序元素分为,公用元素和私用元素

包由两部分组成:包规范和包体

包规范,用于定义包的公用元素,包括常量、变量、游标、过程、函数等

包体,用于实现包规范所定义的公用过程和函数。包体不仅用于实现公用过程和函数,还可定义私用元素。

包规范语法格式:

CREATE [OR REPLACE] PACKAGE package_name

IS|AS

--定义公用常量、变量、游标、过程、函数等

END [package_name]

包体语法格式:

CREATE [OR REPLACE] PACKAGE BODY package_name

IS|AS

--定义私有常量、变量、游标、过程、函数等

--实现公有过程和函数

END [package_name]

例子:

--创建包规范

CREATE OR REPLACE PACKAGE first_package

IS

  v_no emp.deptno%TYPE:=10;

  --过程

  PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no, v_avgsal OUT NUMBER, v_cnt OUT NUMBER);

END first_package;

--创建包体

CREATE OR REPLACE PACKAGE BODY first_package

IS

  PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no, v_avgsal OUT NUMBER, v_cnt OUT NUMBER);

  IS

  BEGIN

    SELECT AVG(sal),COUNT(*)

    INTO v_avgsal,v_cnt

    FROM emp

    WHERE deptno=v_deptno;

EXCEPTION

WHEN NO_DATA_FOUND THEN

  DBMS_OUTPUT.PUT_LINE(‘没有此部门);

    WHEN OTHERS THEN

    DBMS_OUTPUT.PUT_LINE(SQLERRM);

END;

--调用

DECLARE

  v_avgsal NUMBER;

  v_cnt   NUMBER;

BEGIN

  First_package.query_emp(20,v_avgsal,v_cnt);

  DBMS_OUTPUT.PUT_LINE(‘平均工资||v_avgsal);

  DBMS_OUTPUT.PUT_LINE(‘总人数||v_cnt);

END;

那么包的调用或删除、子程序重载等,我就发发懒不做详细介绍了,希望你能触类旁通,举一反三

触发器

触发器是指存放在数据库中,并且被隐含执行的存储过程。

当发生特定事件时,oracle会自动执行触发器的相应代码。

触发器类型:

  1. DML触发器
  2. DDL触发器
  3. 替代触发器
  4. 系统触发器

触发器的组成

  1. 触发事件:即在何种情况下触发TRIGGER
  2. 触发时间:即该TRIGGER是在触发事件发生之前还是之后触发
  3. 触发器本身:即该TRIGGER被触发之后的目的和意图,正是触发器本身要做的事情
  4. 触发频率:说明触发器内定义的动作被执行的次数

DDL触发器

当创建、修改或删除数据库对象时,也会引起相应的触发器操作事件,而此时就可以利用触发器来对这些数据库对象的DDL操作进行监控。

创建DDL触发器的语法格式:

CREATE [OR REPLACE] TRIGGER 触发器的名称

[BEFORE | AFTER | INTEAD OF] [DDL事件] ON [DATABASE | SCHEMA]

[WHEN触发条件]

[DECLARE]

  [程序的声明部分]

BEGIN

  程序的代码部分

END

例子:禁止scott用户的DDL操作

CREATE OR REPLACE TRIGGER scott_trigger

BEFORE DDL

ON SCHEMA

BEGIN

  RAISE_APPLICATION_ERROR(-20005,’scott用户禁止使用所有的DDL操作’)

END

RAISE_APPLICATION_ERROR是用来测试的异常处理。

RAISE_APPLICATION_ERROR是将应用程序专有的错误从服务器端传达到客户端应用程序

例子:实现对数据库对象操作的日志记录

先创建记录操作的日志表

create table object_log

(logid number constraint pk_logid primary key,

operatedate date not null,

objecttype varchar2(50) not null,

objectowner varchar2(50) not null)

再给表创建一个序列

create sequence object_log_seq

创建触发器

create or replace trigger object_trigger

after create or drop or alter

on database

begin

  insert into object_log(logid, operatedate, objecttype, objectowner)

  values(object_log_seq.nextval,sysdate,ORA_DICT_OBJ_TYPE, ORA_DICT_OBJ_OWNER)

end

DDL触发器事件的属性函数

ORA_DICT_OBJ_TYPE 触发DDL的数据库对象的类型

ORA_DICT_OBJ_OWNER 触发DDL的数据库对象的用户

DML触发器是指基于DML操作所建立的触发器。

DML触发器作用可用于实现数据安全保护、数据审计、数据完整性、参照完整性、数据复制等功能。

DML触发器类型分:语句触发器和行触发器

语句触发器:在指定的操作语句语句之前或之后执行一次,不管这条语句影响了多少行。

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

    :old表示操作该行之前,这一行的值

    :new表示操作该行之后,这一行的值

创建DML触发器的语法格式:

CREATE [OR REPLACE] TRIGGER 触发器的名称

{BEFROE | AFTER}

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

ON 表名

[FOR EACH ROW [WHEN(条件)]]        --行级触发器

PL/SQL

例子1,实现数据安全保护:禁止在休息日改变emp表的数据

分析:时间,to_char(sysdate,’day’)

          采用语句触发器

CREATE OR REPLACE TRIGGER emp_trigger

BEFORE INSERT OR UPDATE OR DELETE

ON emp

BEGIN

  IF to_char(sysdate,’day’) IN (‘星期六’,’星期日) THEN

RAISE_APPLICATION_ERROR(-20006,’不能在休息日改变员工信息);

  END IF;

END;

例子2,实现数据审计功能:审计员工信息表数据的变化,审计删除时间,以及被删除的雇员名。

CREATE TABLE delete_emp_audit(name VARCHAR2(10), delete_time DATE)

CREATE OR REPLACE TRIGGER del_emp_trigger

AFTER DELETE ON emp

FOR EACH ROW

BEGIN

  INSERT INTO delete_emp_audit VALUES(:old.ename, SYSDATE);

END

例子3,实现数据完整性:要求员工涨后工资不能低于原来工资,并且所涨的工资不能超过原工资的50%

CREATE OR REPLACE TRIGGER tr_check_sal

BEFORE UPDATE OF sal ON emp

FOR EACH ROW

WHEN (new.sal<old.sal OR new.sal>old.sal*1.5 )

BEGIN

  RAISE_APPLICATION_ERRORR(-20028,’工资只升不降,并且升幅不能超过50%’);

END;

例子4,实现参照完整性:级联更新dept表的主键列以及emp表的外部键列

参照完整性是指在两张表之间具有主从关系。

为了实现级联删除,可以在定义外部键约束时指定ON DELETE CASCADE关键字。

但使用约束却不能实现级联更新,为了实现级联更新,需要使用触发器。

CREATE OR REPLACE TRIGGER upd_cascade_trigger

AFTER UPDATE OF deptno

ON dept

FOR EACH ROW

BEDIN

  UPDATE emp SET deptno=:new.deptno WHERE deptno=:old.deptno;

END;

替代触发器适用于视图上的一种触发器。

在简单视图上往往可以执行INSERTUPDATEDELETE操作。但在复杂视图上执行这些操作是有限制的。

为了在这些复杂视图上执行这些操作,需要建立替代触发器。

替代触发器的限制:

替代触发器只适用于视图

替代触发器不能指定BEFORE和AFTER选项

不能在具有WITH CHECK OPTION选项的视图上建立替代触发器

替代触发器必须包含FOR EACH ROW选项

例子:

CREATE OR REPLACE VIEW emp_dept

AS

SELECT d.deptno,d.dname,e.empno,e.ename FROM dept d,emp e WHERE d.deptno=e.deptno

CREATE OR REPLACE TRIGGER instead_of_trigger

INSTEAD OF

INSERT

ON emp_dept

FOR EACH ROW

DECLARE

  v_temp INT;

BEGIN

  SELECT COUNT(*) INTO v_temp FROM dept WHERE deptno=:new.deptno;

  IF v_temp=0 THEN

    INSERT INTO dept(deptno,dname)VALUES(:new.deptno,:new.dname);

  END IF;

  SELECT COUNT(*) INTO v_temp FROM emp WHERE empno=:new.empno;

  IF v_temp=0 THEN

    INSERT INTO emp(empno,ename,deptno)VALUES(:new.empno,:new.ename,:new.deptno);

  END IF;

END;

系统触发器是有特定系统事件所触发的触发器。

系统事件是指与例程或方案相关的数据事件,他包括STARTUP、SHUTDOWN、DB_ROLE_CHANGE 和 SERVERERROR

STARTUP事件触发器在启动数据库后触发

SHUTDOWN事件触发器在关闭数据库之前触发

DB_ROLE_CHANGE事件触发器在改变角色后第一次打开数据库时触发

SERVERERROR事件触发器在发生oracle错误时触发

例子:

CREATE TABLE event_table(event VARCHAR2(50),event_time date)

CREATE OR REPLACE TRIGGER startup_trigger

AFTER STARTUP NO DATABASE

BEGIN

  INSERT INTO event_table VALUES(ora_sysevent,SYSDATE);

END;

RENAME COLUMN

猜你喜欢

转载自www.cnblogs.com/outmanxiaozhou/p/10177812.html