0
点赞
收藏
分享

微信扫一扫

Oracle数据库笔记(自用)

木匠0819 2022-03-14 阅读 42

sqlplus的使用: 开启相关服务–sqlplus 用户名/口令 as sysdba --show user --用户切换
SQL的组成: DQL,DDL,DML,DCL
表的创建: create table tablename as select;
create table tablename(columnname datatype [constraint_type],);

student(学号,姓名,性别,出生日期,所在系名称)

student(s_id char(12),s_name varchar2(20),s_gender char(2),s_birth date ,s_depart_name varchar2(20));

create table student
(s_id char(12),
s_name varchar2(20),
s_gender char(2),
s_birth date,
s_depart_name varchar2(20));

teacher(t_id char(6),t_name,t_gender,t_birht,t_depart_name);

create table test
(t_id int,
t_name varchar2(20),
t_address varchar2(300));

数据完整性: 作用是保证表中的数据都是正确的数据。实体完整性,引用完整性,用户自定义完整性。

如何实现数据完整性? 约束,触发器,门电路

约束: 主键,唯一性,检查,非空,外键,默认值。

主键: 特点: 约束列列值不能为空,不能重复;一个表最多有一个主键约束。primary key

create table student
(s_id char(12) primary key,
s_name varchar2(20),
s_gender char(2),
s_birth date,
s_depart_name varchar2(20));

惟一性: 特点: 约束列列值不能重复。unique
create table student
(s_id char(12) primary key,
s_name varchar2(20) unique,
s_gender char(2),
s_birth date,
s_depart_name varchar2(20));

惟一性约束列列值能不能包含多个空值? 可以。

空值: 其不代表任何一个具体值,当空值参与运算时,结果永远为空,通常用 null表示空值。
null>3 null<6 null+4 null-3 null=null? 不相等

9.7内容:

解锁scott用户: 通常由 sys完成。
alter user scott identified by oracle account unlock;

alter user scott identified by tiger; --修改用户口令,通常由用户本身执行
alter user scott account unlock|lock; --解锁|锁定账户,通常由管理员执行。

约束(续)
(3)非空约束。约束列列值不能为空。 not null

create table student
(s_id char(12) primary key,
s_name varchar2(20) unique not null,
s_gender char(2) not null,
s_birth date,
s_depart_name varchar2(20));

(4)检查约束: 属性的值需要特定的条件。 check(条件)

create table student
(s_id char(12) primary key,
s_name varchar2(20) unique not null,
s_gender char(2) check (s_gender=‘男’ or s_gender=‘女’),
s_birth date,
s_depart_name varchar2(20));

create table student
(s_id char(12) primary key,
s_name varchar2(20) unique not null,
s_gender char(2) check (s_gender in(‘男’,‘女’)) ,
s_birth date default sysdate,
s_depart_name varchar2(20));

s_gender能不能为空值? 可以

(5) 外键约束:用来建立表与表之间的关联。外键约束列列值必须在引用列列值范围内;引用列列值具有唯一性,外键约束列和引用列的数据类型和宽度保持完全一致。主表和从表。foreign key(约束列) references 主表(引用列)

course(c_id,c_name,c_credit)
score(s_id,c_id,s_score)

create table score
(s_id char(12) references student(s_id) , -列级约束
c_id char(10) referneces course(c_id),
s_score number(4,1),
constraint pk_score_s_id_c_id primary key(s_id,c_id) --表级约束
);

约束的完整格式: constraint constraint_name constraint_type(constraint_column,) pk_ ck_ uk_ fk_

create table score
(s_id char(12) references student(s_id) , -列级约束
c_id char(10) referneces course(c_id),
s_score number(4,1),
constraint pk_score_s_id_c_id primary key(s_id,c_id) --表级约束
);

s_id,c_id的外键约束由列级转化为表级。

create table score
(s_id char(12) ,
c_id char(10),
s_score number(4,1),
constraint pk_score_s_id_c_id primary key(s_id,c_id),
constraint fk_s_id foreign key(s_id) references student(s_id),
constraint fk_c_id foreign key(c_id) references course(c_id)
);

(6)默认值。 default 值 depart_name varchar2(20) default ‘信息科学与工程学院’

约束添加: (1)非空约束的添加。alter table tablename modify columnname not null;
alter table score modify s_score not null;
(2)其它约束的添加。
alter table tablename add constraint constraint_name constraint_type(constraint_column,);

create table score
(s_id char(12),
c_id char(10),
s_score number(4,1));

alter table score add constraint pk_s_id_c_id primary key(s_id,c_id);

约束的删除,禁用和启用

alter table tablename drop|disable|enable constraint_name;

9.13内容:

查看表的结构: desc tablename

解锁scott用户: 通常由管理员完成 。

alter user scott identified by tiger account unlock;

分解: alter user scott account unlock; 解锁用户

   alter user scott identified by tiger;修改用户口令 。

修改表: alter table tablename . 可以做的操作:添加新列,修改已有列属性,删除已有列。

数据准备: create table test(id int primary key);

(1)添加新列: alter table tablename add (columnname datatype [constraint_type],);
向 test表添加name列,同时限制非空。

alter table test add name varchar2(20) not null;

(2)修改已有列属性: 可以修改列的数据类型和宽度。
alter table tablename modify columnname new_datatype;

name列修改为 char(30)
alter table test modify name char(30);

(3)删除已有列: alter table tablename drop column columnname;

alter table test drop column name;

删除表 : drop table test [cascade constraint];

注意:删除列和删除表的操作都是不可逆的,一定要事先备份。通常在空闲时间完成数据库维护工作。

9.14内容:

DML: insert ,update,delete

(1) 向表中添加数据: Insert。
方法一: Insert into tablename(列名1,) values(值1,,,);

基础表: test(id int primary key,name varchar2(20) )

(1,‘a’) (2)

insert into test(id,name) values(1,‘a’);
insert into test values(1,‘a’);

insert into test(name,id) values(‘d’,4);
insert into test values(‘d’,4); --错误。

insert into test(id) values(2);
insert into test(name) values(‘c’); --错误,没有给主键约束列赋值。

方法二: 一次添加多条记录。 insert into tablename select ;

(5,‘a’)
(6,‘b’)
(7,‘c’)

insert into test select 5,‘a’ from dual union select 6,‘b’ from dual union select 7,‘c’ from dual;

(2) 数据更新: update update tablename set 列名=新值[,] [where条件];

把test表的所有姓名修改为d。
update test set name=‘d’;

把id是5的姓名改成d.

update test set name=‘d’ where id=5;

(3)数据删除: delete . delete from tablename [where 条件];

delete from test;
delete from test where id=5;

事务: 所有的事务在没有完成之前,其他用户应该看不到事务的结果。每一个DDL语句都是一个完整的事务。DML操作需要一个确认的过程(确认提交commit,确认撤销rollback).

作业: 自行设计一个实验,验证所有约束的功能,提交实验过程文档,文件命名格式: 学号+姓名.txt。

如何记录实验过程:
spool 文件名 [append]
实验过程
spool off

9.21内容:

补充: 添加日期型数据。
test(id,name,birth)

1,c, 1978.12.1
insert into test(id,name,birth) values(1,‘c’,‘1-12月-1978’);
更加通用的方法:
insert into test(id,name,birth) values(1,‘c’,date’1978-12-1’);

select sysdate from dual;

首先认识两个表: emp,dept

从最简单的查询讲起: select from;
(1)查询所有信息。 用*。

select * from emp;
select * from dept;

select * from tab; //查询当前用户下有哪些表?

(2)特定属性。多个属性之间用逗号分隔。

查看员工的工号empno 和参加工作时间 hiredate。

select empno,hiredate from emp;

(3)去掉重复记录。distinct.
select deptno from emp;
select distinct deptno from emp;

select distinct deptno,sal from emp;

(4) 连接运算符: ||
查看每个员工的工资,显示结果为: XXXX员工的工资是:XXXX

select ename,‘员工的工资是:’,sal from emp;

select ename||‘员工的工资是:’||sal from emp;

条件查询: select from where;

(1)简单条件表达式。用简单的比较运算符(> = < !=)组成的条件表达式

查询20号deptno部门员工的姓名ename,工资sal 和奖金comm。

select ename,sal,comm from emp where deptno=20;

(2)复合条件表达式。由逻辑运算符(not ,and ,or)连接的多个条件。

查询20号、30号deptno部门员工的姓名ename,工资sal 和奖金comm。
deptno=20 or deptno=30 deptno in(20,30)

(3)几个特殊的比较运算符: in,between and,like,is
in: 几个中一个,通常用in. a in(b,c,d)

betwee and: 是一个连续的值域。
查询20号部门工资在2000到3000之间的员工的姓名。
select ename from emp where deptno=20 and sal between 2000 and 3000;

is运算符: 查询属性列的值为空值的情形。is null is not null deptno in (10)

like运算符: 模糊查询。两个通配符: % 任意个字符, _ 任意一个字符。

查询员工姓名的第二个字符为A的员工的姓名ename和参加工作时间 hiredate。

select ename,hiredate from emp where ename like ‘_A%’; A %A%

注意: Oracle是大小写不敏感的,但当字符型数据出现在条件表达式中时,必须严格区分大小写。

9.27内容:
(1)查询结果排序: select from where order by ; 默认是升序asc,可以用desc改为降序输出.

order by a asc,b desc

查询20号部门工资超过2000的员工的姓名,参加工作时间,按工资升序输出,若工资相同,则按参加工作时间降序输出。

select ename,hiredate from emp where deptno=20 and sal>2000 order by sal asc,hiredate desc;

(2)空值处理函数: nvl(a,b) ,若a非空,返回a,否则返回b.

查询每个员工的年收入。 sal comm sal+comm

select ename,(sal+comm)*12 from emp;

select ename,(sal+nvl(comm,0))*12 from emp;

列别名: 列名 空格 别名 ; 列名 as 别名

(3)年龄或者工龄的计算。 查询每个员工的工龄。hiredate sysdate

方法一: (sysdate-hiredate)/365

方法二: months_between(sysdate,hiredate)/12

方法三: to_char(日期型数据,‘format’) format: yyyy, mm, ddd, dd, d ,hh,mi,ss, hh24

以 年-月-日 时:分:秒 的形式输出当前时间。

select to_char(sysdate,‘yyyy-mm-dd hh:mi:ss’) from dual;

to_char(sysdate,‘yyyy’)-to_char(hiredate,‘yyyy’)

10.11内容:

函数: 单行函数和聚集函数(分组函数)。

分组函数: count,min,max,sum,avg

注意: (1) 有一个函数的参数可以为*,count()
(2) 有两个函数的参数类型要求必须是数值型: sum,avg
(3) 除count(
)外,所有函数忽略空值。
(4) 分组函数可以出现在查询的select,having,order by从句中。

查询一个用户下有多少个对象? select * from tab;

select count(*) from tab;

select count(tname) from tab;

select count(1) from tab;

查询emp表中有多少个员工?

select count(empno) from emp;

查询每个部门的员工数。
select deptno,count(empno) from emp;

把语句分解: select deptno from emp; 14
select count(empno) from emp; 1

在查询中,既有单值列,又有分组函数时,所有出现的单值列必须作为分组列处理。分组用group by从句。

select deptno,count(empno) from emp group by deptno;

select deptno,sal,count(empno) from emp group by deptno,sal;

现在学习的简单查询格式: select from where group by order by;

查询哪些部门员工数超过3? count(empno)>3

select deptno,count(empno) from emp where count(empno)>3 group by deptno;

错误分析: (1)从分组函数的使用规则方面。

      (2)回答一个问题: count(empno)的值什么时候获得? 分组后再计算。

上边的需求是对分组后的结果做进一步的筛选,需要用having从句。having是随着group by 的出现而出现的,其不能单独使用。

select deptno,count(empno) from emp group by deptno having count(empno)>3 ;

查询20号、30号部门哪些部门员工数超过3? deptno in(20,30)

where和having? 带有分组函数的条件出现在having中,其他均出现在where从句。

select deptno,count(empno) from emp where deptno in(20,30) group by deptno having count(empno)>3 ;

select deptno,count(empno) from emp group by deptno having count(empno)>3 and deptno in(20,30);

简单查询的完整格式: select from where group by having order by;

10.12内容:

(1)查询中实现if else功能。

实例:查询每个部门的名称,若部门名为accounting,则显示财务处,若部门名为sales,显示销售部,否则显示其它部门。

方法一: Decode函数,格式: decode(a,b,c,d),如果a=b,返回c,否则返回d.
decode(a,b,c,d,e,f,g)

select deptno,decode(lower(dname),‘accounting’,‘财务处’,‘sales’,‘销售部’,‘其它部门’) 部门名称 from dept;

方法二: case语句

形式1: 简单case语句。

case 表达式
when value1 then return1
when value2 then return2

else return N
end

select deptno,
case lower(dname)
when ‘accounting’ then ‘财务处’
when ‘sales’ then ‘销售部’
else ‘其它部门’
end 部门名称
from dept;

形式2:搜索case语句

case when 条件表达式1 then return1
when 条件表达式2 then return2

else returnN
end

select deptno,
case
when lower(dname)=‘accounting’ then ‘财务处’
when lower(dname)=‘sales’ then ‘销售部’
else ‘其它部门’
end 部门名称
from dept;

(2) 查询结果的集合运算. (union all,union,intersect, minus),进行集合运算的查询必须具有相同的属性个数和属性类型。

select distinct deptno from dept 10 20 30 40
union all
select distinct deptno from emp; 10 20 30

union all 10 20 30 40 10 20 30
union 10 20 30 40
intersect 10 20 30
minus 40

(3)特定记录查找。 如 : 查询emp表的第5-10条记录 查询emp表的第5,7,9条记录

如何查询前几条记录?

引入rownum: rownum是一个伪列,给表的每一行加一个序号。当其出现在where子句中时,值总是从1开始。< <= =1

(select * from emp where rownum<=5 minus select * from emp where rownum<5)
union
(select * from emp where rownum<=7 minus select * from emp where rownum<7)
union
(select * from emp where rownum<=9 minus select * from emp where rownum<9);

10.18内容:

连接查询: 需要查询的数据来源于多个表,连接查询需要书写连接条件,N个表连接至少需要N-1个连接条件。分为内连接和外连接,内连接分为等值连接、不等连接和自连接;外连接分为左外、右外和全外连接。

内连接:只输出满足连接条件的记录。

(1)等值连接: 要连接的两个表之间有公共列(列的数据类型和宽度一致),形式为: tableA.column1=tableB.column2

查询所有员工的工号、姓名和所在部门名称。

select empno,ename,emp.deptno,dname
from emp,dept
where emp.deptno=dept.deptno;

select emp.empno,emp.ename,emp.deptno,dept.dname
from emp e,dept d
where emp.deptno=dept.deptno;

select e.empno,e.ename,e.deptno,d.dname
from emp e,dept d
where e.deptno=d.deptno and e.deptno=10; deptno=10 and e.deptno=d.deptno(效率不高)

注意:(a) 解决列的二义性问题。对于连接查询中出现的每个属性都添加归属对象。

  (b)表别名:表名 空格 别名 .表别名一经定义,在该查询中只能使用该别名,表原名不可再用;列别名只能出现在select、order by从句中。

select deptno,avg(sal) a from emp group by deptno having avg(sal)>3000 order by a;

(2) 不等连接:两个表之间没有公共列。

查询每一个员工的工资等级。

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

(3)自连接: 数据来源于同一个表。

查询每个员工姓名及其经理名。

select e.ename,m.ename
from emp e,emp m
where e.mgr=m.empno;

外连接: 除了输出满足连接条件的记录,部分不满足连接条件的记录也会输出。引入了外连接运算符(+),该运算符添加到信息缺失一方。

select e.ename,m.ename
from emp e,emp m
where e.mgr=m.empno(+); --左外连接,信息完整方所在位置。

select e.ename,m.ename
from emp e,emp m
where m.empno(+)=e.mgr; --右外连接

SQL99连接语法:

inner join tableA inner join tableB on 连接条件 where
outer join left|right|full outer join

10.19内容:

子查询:一个查询a包含在其它查询b中,则该查询a称为子查询。子查询可以嵌套,一般不要超过3层。子查询可以出现在from、where、having从句中。

分类: 单行子查询、 多行子查询、多列子查询、相关子查询。

单行子查询: 子查询的结果最多只有一个。

查询哪些员工的工资比7788员工的工资高。

select sal from emp where empno=7788; 2000

select ename from emp where sal>(select sal from emp where empno=7788);

多行子查询: 子查询的结果不止1个。需要引入多行子查询运算符,in,any,all(in单独使用,any,all需要结合单值比较运算符使用)

查询哪些员工工资比20号任一员工工资高。>any
select ename,sal from emp where sal>any(select sal from emp where deptno=20);
>(select min(sal) from emp where deptno=20)

查询哪些员工工资比20号任意员工工资高。>all

select ename,sal from emp where sal>all(select sal from emp where deptno=20); >max(sal)

多列子查询: 查询哪些员工的工资和奖金比7788员工的工资、奖金高。

select ename from emp where sal>(select sal from emp where empno=7788) and nvl(comm,0)>(select nvl(comm,0) from emp where deptno=7788);

select ename from emp where (sal,comm)>(select sal,comm from emp where empno=7788);

10.26日内容: 数据库对象管理(表,视图,索引,序列号,同义词) select * from tab;

表: 通过查询建表: create table tablename as select;

给dept表做一个备份: create table dept_bak as select * from dept;
create table dept_bak1 as select * from dept where 1=2;
insert into dept_bak1 select * from dept where deptno=10;

               create table avgsal as select deptno,avg(sal) avg_sal from emp group by deptno;

视图: 本质上是一个虚表,其不包含任何数据,所有查询到的数据来源于创建视图的基表。学会创建只读视图。

注意: 普通用户要创建视图,需要由管理员授权: grant create view to 用户名;

语法:

create [or replace] view viewname[(列名1,)]
as select
[with check option]
[with read only];

简化版视图创建: create view viewname as select;

create view dept_view as select * from dept;

create view view_avgsal1 as select deptno,avg(sal) avg_sal from emp group by deptno;

create view dept_view1 as select * from dept with read only;

drop view viewname;

几个系统视图: user_tables, user_constraints, user_views , user_objects, user_indexes
all_tables, all_constraints,all_views
dba_tables, dba_constraints,dba_views

11.1内容:

索引和序列号。

索引:提升查询效率。索引不是越多越好,因为索引需要维护。索引表。索引创建完成后,由系统根据优化器的优化规则自动选择是否使用索引;作为程序员来说,要使创建的索引能够尽可能的使用,应保证索引列按顺序出现在条件语句中。主键和唯一性约束列系统自动创建唯一性索引。

创建索引: create [unique] index index_name on tablename(列名1 [desc],);

在emp(ename)列创建一个普通索引。
create unique index idx_ename on emp(ename desc);

create index idx_sal_hiredate on emp(sal desc,hiredate);

create index idx1 on emp(lower(ename));

select * from emp;

select * from emp where ename=‘SMITH’;

select * from emp where sal>2000;

select * from emp where hiredate>date’1983-1-1’;

select * from emp where sal>2000 and hiredate>date’1983-1-1’;

select * from emp where lower(ename)=‘smith’;

序列号: 通常是为主键服务,自动生成序号。

创建语法:
create sequence sequence_name
[start with m
increment by n
maxvalue A
minvalue B
cycle|nocycle
cache C];

create sequence seq1;

create sequence seq2 start with 2 increment by 2;

序列的使用: 两个属性: currval,nextval. 使用方法: 序列号名.属性名 seq1.nextval. 序列号初次使用,必须用nextval初始化。

create table test(id int primary key);

insert into test values(seq1.nextval);

alter sequence: 除初值外,其它参数都可以修改。 drop sequence ;

11.9内容:用户管理(一般由管理员完成)。
创建用户: create user username identified by password;
修改用户: alter user username identifie by password;
删除用户: drop user username;

新建一个test,并切换到test.
create user test identified by oracle;
connect test/oracle

权限管理: 系统权限和对象权限。

系统权限: 对数据库进行操作的权利。create table,create session,create any table,alter table,drop table,create view

授予用户系统权限: grant 权限名, to username1, [with admin option];

grant create session,create table,unlimited tablespace to test with admin option; test1
注意: with admin option的功能是: test可以把它所被授予的系统权限给其它任何一个用户。 sys—test—test1

回收权限: revoke 权限名 from username;
revoke create session,create table,unlimited tablespace from test; sys test—test1

注意: 系统权限的回收不具有级联性。

对象权限: 针对某个用户下对象的操作能力,通常由对象的所有者进行授权。select ,insert,update,delete ,execute

对象权限的授予: grant 权限名 on 对象名 to username,[ with grant option];

把查询dept表的权限给test.
conn scott/tiger
grant select on dept to test with grant option; scott—test—test1
conn test/oracle
select * from scott.dept;

注意: 对象权限的回收具有级联性。

角色管理:role ,引入的目的是提升权限管理的效率。resource,connect,sysdba,sysoper

100个权限,需要授予100个用户。一次只能授予一个权限。 100*100

引入一个角色,先把100个权限放到角色中,再把角色授予用户。

100priv 1role 100user 100+100

11.15内容:PL/SQL语言 procedure language.

块: 块的组成:

声明部分–变量、常量、数据类型、游标等的声明—declare
执行部分–块的功能实现------------------------begin
异常处理部分–程序中可能出现的错误的预处理。—exception
end;

begin

end;

从一个简单的程序看起: hello world

begin
dbms_output.put_line(‘hello world’);
end;
/
开启屏幕打印: set serveroutput on

declare
v_string varchar2(20);
begin
v_string:=‘hello world’;
dbms_output.put_line(v_string);
end;

SQL语句哪些能够出现在块中? DML可以直接出现;DDL不可以直接出现;select from语句以select into from的形式出现。

变量的声明:
(1)普通变量声明: 变量名 数据类型 [:=value1|default value2]; 建议以v_开头,不能使用系统保留字。v_sum,v_avg

数据类型: number,char,varchar2,date,boolean(true,false,null).

写一个PL/SQL程序,输出7788员工的姓名。select ename from emp where empno=7788;

set serveroutput on
declare
v_ename varchar2(20);
begin
select ename into v_ename from emp where empno=7788;
dbms_output.put_line(‘7788员工的姓名:’||v_ename);
end;
/

写一个PL/SQL程序,输出20号部门员工的平均工资和平均奖金。
declare
v_avgsal number(7,2);
v_avgcomm number(7,2);
begin
select avg(sal),avg(nvl(comm,0)) into v_avgsal,v_avgcomm from emp where deptno=20;
dbms_output.put_line(‘20号部门员工的平均工资:’||v_avgsal||’ '||‘平均奖金:’||v_avgcomm);
end;

(2)声明一个变量与已有变量数据类型一致。变量名 已有变量名%type; 声明一个变量与表中某列属性保持一致。

v_ename char2(20);
v_ename1 char2(20);
v_ename2 char2(20);

v_ename char2(30);
v_ename1 v_ename%type;
v_ename2 v_ename%type;

v_avgsal emp.sal%type;
v_avgcomm emp.comm%type;

写一个PL/SQL程序,输出20号部门部门信息.dept(deptno,dname,loc)

declare
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_loc dept.loc%type;
begin
select * into v_deptno,v_dname,v_loc from dept where deptno=20;
dbms_output.put_line(v_deptno||‘号部门的部门名称:’||v_dname||’ '||‘部门所在地:’||v_loc);
end;

(3)声明一个变量,与一个表结构保持一致。记录变量名 表名%rowtype; 记录变量名建议以rec_开头。
declare
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_loc dept.loc%type;
begin
select * into v_deptno,v_dname,v_loc from dept where deptno=20;
dbms_output.put_line(v_deptno||‘号部门的部门名称:’||v_dname||’ '||‘部门所在地:’||v_loc);
end;

declare
rec_dept dept%rowtype;
begin
select * into rec_dept from dept where deptno=20;
dbms_output.put_line(rec_dept.deptno||‘号部门的部门名称:’||rec_dept.dname||’ '||‘部门所在地:’||rec_dept.loc);
end;

(4) 结合变量

variable 变量名 数据类型;
execute :变量名:=value;
print :变量名;

11.16内容:

1、分支结构

(1)if语句。

if 条件 then 表达式 end if;

if 条件 then 表达式1 else 表达式2 end if;

if 条件1 then 表达式1 elsif 条件2 then 表达式2 else 表达式N end if;

查询7788员工的工资,若工资超过3000,显示高工资,2000到3000之间,显示中等工资,否则显示低工资。

declare
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=7788;
if v_sal>3000 then
dbms_output.put_line(‘7788员工的工资等级为高工资’);
elsif v_sal between 2000 and 3000 then
dbms_output.put_line(‘7788员工的工资等级为中等工资’);
else
dbms_output.put_line(‘7788员工的工资等级为低工资’);
end if;
end;

(2)case语句。

简单case语句:
case 表达式
when value1 then 语句块1;
when value2 then 语句块2;

else 语句块N;
end case;

查询20号部门的部门名称,若名称为 accounting,显示财务处,为sales,显示销售部,否则显示其他部门。

select dname from dept where deptno=20;

declare
v_dname dept.dname%type;
begin
select dname into v_dname from dept where deptno=20;
case v_dname
when ‘ACCOUNTING’ then
dbms_output.put_line(‘财务处’);
when ‘SALES’ then
dbms_output.put_line(‘销售部’);
else
dbms_output.put_line(‘其他部门’);
end case;
end;

搜索case语句:

case
when 条件1 then 语句块1;
when 条件2 then 语句块2;

else 语句块N;
end case;

declare
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=7788;
case
when v_sal>3000 then
dbms_output.put_line(‘7788员工的工资等级为高工资’);
when v_sal between 2000 and 3000 then
dbms_output.put_line(‘7788员工的工资等级为中等工资’);
else
dbms_output.put_line(‘7788员工的工资等级为低工资’);
end case;
end;

向dept表添加一条记录,若该记录存在,则提示记录已存在,若不存在,则添加记录并提交。
select count(deptno) from dept where deptno=50;

declare
v_count int;
v_deptno dept.deptno%type;
begin
v_deptno:=50;
select count(deptno) into v_count from deptno where deptno=v_deptno;
if v_count=1 then
dbms_output.put_line(v_deptno||‘号部门已存在’);
else
insert into dept values(v_deptno,‘xinxi’,‘linyi’);
commit;
end if;
end;

2、循环结构

简单循环:
loop
循环体;
exit when 条件;
end loop;

while循环:
while 条件
loop
循环体;
end loop;

for循环:

for 循环控制变量 in [reverse] 下限…上限
loop
循环体;
end loop;
注意事项: (1)循环控制变量不需要事先声明; (2) 循环控制变量的值不可以在循环体内容改变。

计算1+2+…+100的和。

简单循环:

declare
v_i int:=1;
v_sum int:=0;
begin
loop
v_sum:=v_sum+v_i;
v_i:=v_i+1;
exit when v_i>100;
end loop;
dbms_output.put_line(‘1+2+…+100=’||v_sum);
end;

declare
v_i int:=0;
v_sum int:=0;
begin
loop
v_i:=v_i+1;
exit when v_i>100;
v_sum:=v_sum+v_i;
end loop;
dbms_output.put_line(‘1+2+…+100=’||v_sum);
end;

while循环:

declare
v_i int:=1;
v_sum int:=0;
begin
while v_i<=100
loop
v_sum:=v_sum+v_i;
v_i:=v_i+1;
end loop;
dbms_output.put_line(‘1+2+…+100=’||v_sum);
end;

for循环:

declare
v_j int:=1;
v_sum int:=0;
begin
for v_i in 1…100
loop
v_sum:=v_sum+v_j;
v_j:=v_j+1;
end loop;
dbms_output.put_line(‘1+2+…+100=’||v_sum);
end;

思考: 计算100以内偶数的和.

declare
v_j int:=2;
v_sum int:=0;
begin
for v_i in 1…50
loop
v_sum:=v_sum+v_j;
v_j:=v_j+2;
end loop;
dbms_output.put_line(‘1+2+…+100=’||v_sum);
end;

11.22内容:

需求: 写一个PL/SQL程序,输出所有部门的部门信息。select * from dept;

游标: 一个内存区域,引入主要目的就是处理多行查询。分为隐式游标和显式游标。

隐私游标: 在PL/SQL块中,执行DML、select into from子句时,系统自动生成的游标。隐式游标游标名: SQL。
四个属性:

%isopen: 相应SQL语句执行过程中为真,结束为假。
%rowcount: DML所影响的行数。
%found: DML执行成功为真,执行失败为假。
%notfound: DML执行失败为真,成功为假。

更新特定员工的工资,更新成功,则提交并给出相应提示,更新失败,也给出相应提示。

begin
update emp set sal=3000 where empno=1234;
if sql%found then
commit;
dbms_output.put_line(‘更新成功’);
else
rollback;
dbms_output.put_line(‘更新失败’);
end if;
end;

begin
update emp set sal=3000 where empno=7788;
if sql%found then
dbms_output.put_line(‘更新成功’||’ '||‘更新了’||sql%rowcount||‘条记录’);
commit;
else
rollback;
dbms_output.put_line(‘更新失败’);
end if;
end;

显式游标: 用户定义的,用来出来多条记录的查询。

显式游标使用的四个步骤:

声明游标:出现在declare部分,语法: cursor cursor_name is select;
打开游标:open cursor_name; 执行声明游标时对应的子查询,并把结果读入内存块。
提取数据: fetch cursor_name into 变量名,;
关闭游标: close cursor_name; 释放所占用的内存区域。

四个属性:
%isopen: 游标打开为真,未打开为假。
%rowcount: 当前提取的行数。
%found: 提取成功为真,失败为假。
%notfound: 提取失败为真,成功为假。

写一个PL/SQL程序,输出所有部门的部门信息。select * from dept; dept(deptno,dname,loc)

declare
cursor cur1 is select * from dept; --声明cur游标
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_loc dept.loc%type;
begin
open cur1; --打开游标
loop
fetch cur1 into v_deptno,v_dname,v_loc; --提取数据
exit when cur1%notfound;
dbms_output.put_line(v_deptno||'号部门的部门名: ‘||v_dname||’ '||‘部门所在地’||v_loc);
end loop;
close cur1; --关闭游标
end;

while循环:
declare
cursor cur1 is select * from dept; --声明cur游标
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_loc dept.loc%type;
begin
open cur1; --打开游标
fetch cur1 into v_deptno,v_dname,v_loc; --提取数据
while cur1%found
loop
dbms_output.put_line(v_deptno||'号部门的部门名: ‘||v_dname||’ '||‘部门所在地’||v_loc);
fetch cur1 into v_deptno,v_dname,v_loc; --提取数据
end loop;
close cur1; --关闭游标
end;

declare
cursor cur1 is select * from dept; --声明cur游标
rec_cur1 cur1%rowtype; --声明了一个记录变量,与已有的游标类型保持一致。
begin
open cur1; --打开游标
fetch cur1 into rec_cur1; --提取数据
while cur1%found
loop
dbms_output.put_line(rec_cur1.deptno||'号部门的部门名: ‘||rec_cur1.dname||’ '||‘部门所在地’||rec_cur1.loc);
fetch cur1 into rec_cur1; --提取数据
end loop;
close cur1; --关闭游标
end;

FOR循环实现游标记录的提取:

declare
cursor cur1 is select * from dept; --声明cur游标
begin
for rec_cur1 in cur1
loop
dbms_output.put_line(rec_cur1.deptno||'号部门的部门名: ‘||rec_cur1.dname||’ '||‘部门所在地’||rec_cur1.loc);
end loop;
end;

begin
for rec_cur1 in (select * from dept)
loop
dbms_output.put_line(rec_cur1.deptno||'号部门的部门名: ‘||rec_cur1.dname||’ '||‘部门所在地’||rec_cur1.loc);
end loop;
end;

cursor cur2(v_deptno varchar2) is select deptno,avg(sal) avgsal from emp where deptno=v_deptno group by deptno;

open cur2(20);

11.23内容:异常处理。

系统预定义异常: no_data_found, too_many_rows, invalid_cursor,zero_divide,others

语法:
exception
when exp1 then
处理1;
when exp2 or exp3 then
处理2;

when others then
处理N;

set serveroutput on
declare
v_ename varchar2(20);
v_empno emp.empno%type;
begin
v_empno:=7788;
select ename into v_ename from emp where empno=v_empno;
dbms_output.put_line(‘7788员工的姓名:’||v_ename);
exception
when no_data_found then
dbms_output.put_line(v_empno||‘员工不存在’);
when others then
dbms_output.put_line(‘发生未知错误’);
end;
/

如使用others异常,其一定是异常处理的最后一个分支,并可以结合sqlcode()和sqlerrm()函数分别获错误编号和错误提示信息。

用户自定义异常:

(1)三个步骤方法:
声明异常: 异常名 exception;
激活异常 raise 异常名;
处理异常 when 异常名 then
处理;

写一个用户自定义异常,实现zero_divide预定义异常的功能。
declare
v_a number;
v_b number;
v_c number;
zero_divide1 exception;
begin
v_a:=1;
v_b:=2;
if v_b=0 then
raise zero_divide1;
else
v_c:=v_a/v_b;
dbms_output.put_line(v_c);
end if;
exception
when zero_divide1 then
dbms_output.put_line(‘除数不能为0’);
end;

从键盘接收输入的方法:
declare
v_a number;
v_b number;
v_c number;
zero_divide1 exception;
begin
–&符号的作用是代表其后为一个替代变量,变量值在程序运行期间从键盘接收。
v_a:=&v_a;
v_b:=&v_b;
if v_b=0 then
raise zero_divide1;
else
v_c:=v_a/v_b;
dbms_output.put_line(v_c);
end if;
exception
when zero_divide1 then
dbms_output.put_line(‘除数不能为0’);
end;

(2)raise_application_error(错误编号,错误信息); -20000至-20099

declare
v_a number;
v_b number;
v_c number;
begin
–&符号的作用是代表其后为一个替代变量,变量值在程序运行期间从键盘接收。
v_a:=&v_a;
v_b:=&v_b;
if v_b=0 then
raise_application_error(-20001,‘除数不能为0’);
else
v_c:=v_a/v_b;
dbms_output.put_line(v_c);
end if;
end;

写一个用户自定义异常,实现no_data_found和too_many_rows预定义异常的功能。

11.30内容:存储过程、函数、包、触发器。

块分为未命名块和命名块。未命名块的编译和执行都是在客户端完成的。命名块的编译和执行都是在服务器端完成的,编译完成后长时间存储在服务器端,用户可以非常方便的调用。

存储过程: 命名块的一种,没有返回值。

创建存储过程:

create or replace procedure procedure_name[(参数名 参数类型 参数数据类型,)]
is|as
声明部分;
begin
执行部分;
exception
异常处理;
end;

create or replace procedure proc1
is
v_a number;
v_b number;
v_c number;
begin
–&符号的作用是代表其后为一个替代变量,变量值在程序运行期间从键盘接收。
v_a:=&v_a;
v_b:=&v_b;
if v_b=0 then
raise_application_error(-20001,‘除数不能为0’);
else
v_c:=v_a/v_b;
dbms_output.put_line(v_c);
end if;
end;

create or replace procedure proc2
is
begin
dbms_output.put_Line(‘hello world’);
end;

写一个存储过程,输出一共有多少个员工。 select count(*) from emp;

create or replace procedure proc3
is
v_count int;
begin
select count(*) into v_count from emp;
dbms_output.put_line(v_count);
end;

调用存储过程:
(1)execute procedure_name(实参,);
(2) begin
procedure_name(实参,);
end;

存储过程参数类型: in,out ,in out

(1)输入参数

写一个存储过程,输出特定部门员工数。 select count(*) from emp where deptno=v_deptno;

create or replace procedure proc4(v_deptno in deptno%type)
is
v_count int;
begin
select count(*) into v_count from emp where deptno=v_deptno;
dbms_output.put_line(v_count);
end;

exec proc4(10);
begin
proc4(20);
end;
/

(2)输出参数

写一个存储过程,利用输出参数传出特定部门员工数。

create or replace procedure proc5(v_deptno in deptno%type,v_count out int)
is
begin
select count(*) into v_count from emp where deptno=v_deptno;
end;

带有输出参数存储过程的调用:输入参数传的是实际值,输出参数传的是变量名.
declare
v_count1 int;
begin
proc5(10,v_count1);
dbms_output.put_line(v_count1);
end;

variable v_count1 int;
execute proc5(20,:v_count1);
print :v_count1;

12.6内容:

函数: 有且仅有一个返回值。

创建函数:
create or replace function function_name[(参数名 参数类型 参数数据类型,)]
return 数据类型
is|as
声明部分;
begin
执行部分;
return (表达式);
exception
异常处理;
return(表达式);
end;

写一个函数,返回员工表的员工数。

create or replace procedure proc3
is
v_count int;
begin
select count(*) into v_count from emp;
dbms_output.put_line(v_count);
end;

create or replace function fun1
return number
is
v_count number(3);
begin
select count(*) into v_count from emp;
return (v_count);
end;

写一个函数,根据员工名返回员工号。 select empno from emp where ename=v_ename;

create or replace function fun2(v_ename emp.ename%type)
return emp.empno%type
is
v_empno emp.empno%type;
begin
select empno into v_empno from emp where ename=v_ename;
return (v_empno);
exception
when no_data_found then
return (null);
when too_many_rows then
return (null);
end;

函数的调用:
注意: 存储过程没有返回值,函数有返回值,在调用时,存储过程不能作为其他表达式的一部分调用,而函数只能作为其他表达式的 一部分调用。

exec proc4(10);
begin
proc4(20);
end;
调用函数的方法:
(1)variable v_empno1 number;
exec :v_empno1:=fun2(‘SCOTT’);
print :v_empno1;

(2) begin
dbms_output.put_line(fun2(‘SCOTT’));
end;

declare
  v_empno1 emp.empno%type;
begin 
  v_empno1:=fun2('SCOTT');
  dbms_output.put_line(v_empno);
end;

(3) select fun2(‘SCOTT’) from dual;

12.7内容:

触发器: 在满足特定事件时自动执行的一种程序。
根据事件类型不同,分为DML触发器,DDL触发器,替代触发器和数据库事件触发器。

DML触发器: 在特定对象执行特定的DML操作时自动执行。

注意几个问题:
(1) 三个谓词: inserting,updating,deleting
(2)两个伪记录: :old, :new,获取数据更新前后的值。 :old.列名 :old.ename
insert: :new
update: 都可以用
delete: :old
(3) 触发器内不能直接或者间接使用事务处理语句(commit,rollback,savepoint )。

定义DML触发器的步骤: 触发时间、触发事件、触发对象、触发级别(行级和语句级)

创建触发器语法:
create or replace trigger trigger_name
before|after
insert or update or delete
on tablename
[for each row]
[when 条件]
declare
begin
exception
end;

举例: 写一个触发器,实现dept表的联机备份。

create table dept_bak as select * from dept;

create or replace trigger tri1
after
insert or update or delete
on dept
for each row
begin
if inserting then
insert into dept_bak values(:new.deptno,:new.dname,:new.loc);
elsif updating then
update dept_bak set deptno=:new.deptno,dname=:new.dname,loc=:new.loc where deptno=:old.deptno and dname=:old.dname and loc=:old.loc;
else
delete from dept_bak where deptno=:old.deptno and dname=:old.dname and loc=:old.loc;
end if;
end;

举例:用触发器实现外键约束数据的级联更新。
create or replace trigger tri2
after
update of deptno
on dept
begin
update emp set deptno=:new.deptno where deptno=:old.deptno;
end;

限定对emp表的修改,只能修改部门10的雇员工资。

create or replace trigger tri3
before
update of sal
on emp
for each row
when (old.deptno!=10)
begin
raise_application_error(-20002,‘只能修改10号部门员工工资’);
end;

create or replace trigger tri4
before
update
on emp
for each row
when (old.deptno!=10)
begin
raise_application_error(-20002,‘只能修改10号部门员工工资’);
end;

create or replace trigger tri3
before
update of sal
on emp
for each row
begin
if :old.deptno!=10 then
raise_application_error(-20002,‘只能修改10号部门员工工资’);
end if;
end;

举报

相关推荐

0 条评论