1. Oracle 体系结构
Oracle 的概念和别的数据库不太一样,详细介绍下。
1.1 数据库
Oracle 数据库是数据的物理存储。这就包括(数据文件 ORA 或者 DBF、控制文件、联机日志、参数文件。其实 Oracle 数据库的概念和其它数据库不一样,这里的数据库是一个操作系统,只有一个库。可以看作是 Oracle 就只有一个大数据库。数据库是一个比较偏向于硬件的概念。
1.2 实例
一个 Oracle 实例 (Oracle Instance) 有一系列的后台进程 (Backguound Processes) 和内存结构 (Memory Structures) 组成。一个数据库可以有 n 个实例。实例和数据库概念相似,只是一个偏向于软件的单位。一个数据库可以有多个实例,但一般只有一个。
1.3 用户
用户是在实例下建立的。不同实例可以建相同名字的用户。
在 Oracle 中,管理表的基本单位不是数据库,而是用户,每个用户下面可以都多张表。
不能说某个数据库下面有几张表,而应该是某个用户下面有几张表。
1.4 表空间
表空间是 Oracle 对物理数据库上相关数据文件(ORA 或者 DBF 文件)的逻辑映射。一个数据库在逻辑上被划分成一到若干个表空间,每个表空间包含了在逻辑上相关联的一组结构。每个数据库至少有一个表空间 (称之为 system 表空间)。(当数据文件过多时,会划分为多个表空间)
每个表空间由同一磁盘上的一个或多个文件组成,这些文件叫数据文件 (datafile)。一个数据文件只能属于一个表空间。
1.5 数据文件
数据文件是数据库的物理存储单位。数据库的数据是存储在表空间中的,真正是在某一个或者多个数据文件中。而一个表空间可以由一个或多个数据文件组成,一个数据文件只能属于一个表空间。一旦数据文件被加入到某个表空间后,就不能删除这个文件,如果要删除某个数据文件,只能删除其所属于的表空间才行。
表的数据,是有用户放入某一个表空间的,而这个表空间会随机把这些表数据放到一个或者多个数据文件中。
由于 oracle 的数据库不是普通的概念,oracle 是由用户和表空间对数据进行管理和存放的。但是表不是由表空间去查询的,而是由用户去查的。因为不同用户可以在同一个表空间建立同一个名字的表!这里区分就是用户了!
2. Oracle 基本操作
--创建表空间
create tablespace itheima --表空间名
datafile 'c:\itheima.dbf' --数据文件
size 100m --表空间初始大小
autoextend on --存满时,自动增长
next 10m; --自动增长大小
--删除表空间
drop tablespace itheima;
--创建用户
create user itheima --用户名
identified by itheima --密码
default tablespace itheima;--指定用户的表空间
--给用户授权
--oracle数据库中常用角色
connect --连接角色,基本角色
resource --开发者角色
dba --超级管理员角色
--给itheima用户授予dba角色
grant dba to itheima;
3. sql
3.1 分页查询
Oracle 分页查询中有个 rownum 字段,表示行号,在每个表中出现。
每查询出一行记录,就会在该行上加上一个行号,行号从1开始,依次递增,不能跳着走。
----排序操作会影响rownum的顺序
select rownum, e.* from emp e order by e.sal desc --会看到 rownum 是乱序的
----如果涉及到排序,但是还要使用 rownum 的话,我们可以再次嵌套查询。
select rownum, t.* from(
select rownum, e.* from emp e order by e.sal desc) t;
----emp 表工资倒叙排列后,每页五条记录,查询第二页。
----rownum 行号不能写上大于一个正数。因为 rownum 是从 1 开始连续的
select rownum rn, tt.* from(
select * from emp order by sal desc
) tt where rownum<11 and rownnum>5
--所以我们再嵌套一层
select * from(
select rownum rn, tt.* from(
select * from emp order by sal desc
) tt where rownum<11
) where rn>5
4. 视图
视图就是封装了一条复杂查询的语句。
语法:CREATE VIEW 视图名称 AS 子查询 [WITH READ ONLY]
create view empvd as select * from emp
修改视图会修改原表数据
视图的作用?
- 视图可以屏蔽掉一些敏感字段
- 保证总部和分部数据及时统一
5. 索引
概念:索引就是在表的列上构建一个二叉树,达到大幅度提高查询效率的目的,但是索引会影响增删改的效率。
索引分为单列索引和复合 (多列) 索引
---单列索引
---创建单列索引
create index idx_ename on emp(ename);
---单列索引触发规则,条件必须是索引列中的原始值。
---单行函数,模糊查询,都会影响索引的触发。
select * from emp where ename='SCOTT'
---复合索引
---创建复合索引
create index idx_enamejob on emp(ename, job);
---复合索引中第一列为优先检索列
---如果要触发复合索引,必须包含有优先检索列中的原始值。
select * from emp where ename='SCOTT' and job='xx';---触发复合索引
select * from emp where ename='SCOTT' or job='xx';---不触发索引
select * from emp where ename='SCOTT';---触发单列索引。
单列索引触发规则:条件必须是原始值,不能为模糊搜索或者聚合函数。
复合索引触发规则:第一列 (优先检索列) 必须为原始值。
6. pl/sql 编程语言
6.1 简介
pl/sql 编程语言是对 sql 语言的扩展,使得 sql 语言具有过程化编程的特性。
pl/sql 编程语言比一般的过程化编程语言,更加灵活高效。
pl/sql 编程语言主要用来编写存储过程和存储函数等。
---声明方法
---赋值操作可以使用:=也可以使用into查询语句赋值
declare
i number(2) := 10; ---number(2) 为类型
s varchar2(10) := '小明';
ena emp.ename%type; ---引用型变量
emprow emp%rowtype; ---记录型变量,类似于对象
begin
dbms_output.put_line(i); ---输出去语句
dbms_output.put_line(s);
select ename into ena from emp where empno = 7788;
dbms_output.put_line(ena);
select * into emprow from emp where empno = 7788;
dbms_output.put_line(emprow.ename || '的工作为:' || emprow.job); ---||连接输出
end;
6.2 if 判断
---输入小于18的数字,输出未成年
---输入大于18小于40的数字,输出中年人
---输入大于40的数字,输出老年人
declare
i number(3) := ⅈ --- &代表输入,ii 为变量,随便写
begin
if i<18 then
dbms_output.put_line('未成年');
elsif i<40 then
dbms_output.put_line('中年人');
else
dbms_output.put_line('老年人');
end if;
end;
6.3 循环
while 循环
---while循环
declare
i number(2) := 1;
begin
while i<11 loop
dbms_output.put_line(i);
i := i+1;
end loop;
end;
exit 结束循环
---exit循环
declare
i number(2) := 1;
begin
loop
exit when i>10;
dbms_output.put_line(i);
i := i+1;
end loop;
end;
for 循环
---for循环
declare
begin
for i in 1..10 loop
dbms_output.put_line(i);
end loop;
end;
6.4 游标
游标:可以存放多个对象,多行记录。
---输出emp表中所有员工的姓名
declare
cursor c1 is select * from emp;
emprow emp%rowtype;
begin
open c1;
loop
fetch c1 into emprow;
exit when c1%notfound;
dbms_output.put_line(emprow.ename);
end loop;
close c1;
end;
-----给指定部门员工涨工资
declare
cursor c2(eno emp.deptno%type)
is select empno from emp where deptno = eno;
en emp.empno%type;
begin
open c2(10);
loop
fetch c2 into en;
exit when c2%notfound;
update emp set sal=sal+100 where empno=en;
commit;
end loop;
close c2;
end;
----查询10号部门员工信息
select * from emp where deptno = 10;
7. 存储过程
存储过程就是提前已经编译好的一段 pl/sql 语言,放置在数据库端,可以直接被调用。这一段 pl/sql 一般都是固定步骤的业务。
创建存储过程的语法,in/out 代表参数是输入类型参数还是输出类型参数,参数默认 in
create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)]
AS -- 或者 is
begin
PLSQL 子程序体;
End;
----给指定员工涨100块钱
create or replace procedure p1(eno emp.empno%type)
is
begin
update emp set sal=sal+100 where empno = eno;
commit;
end;
select * from emp where empno = 7788;
----测试p1
declare
begin
p1(7788);
end;
in 和 out 类型参数
---out类型参数如何使用
---使用存储过程来算年薪
create or replace procedure p_yearsal(eno emp.empno%type, yearsal out number)
is
s number(10);
c emp.comm%type;
begin
select sal*12, nvl(comm, 0) into s, c from emp where empno = eno;
yearsal := s+c;
end;
---测试p_yearsal
declare
yearsal number(10);
begin
p_yearsal(7788, yearsal);
dbms_output.put_line(yearsal);
end;
in 和 out 类型参数的区别是什么?
凡是涉及到 into 查询语句赋值或者 :=
赋值操作的参数,都必须使用 out 来修饰。
8. 存储函数
存储过程和存储函数的区别?
一般来讲,过程和函数的区别在于函数可以有一个返回值;而过程没有返回值。
但过程和函数都可以通过 out 指定一个或多个输出参数。我们可以利用 out 参数,在过程和函数中实现返回多个值。
创建存储函数语法
create or replace function 函数名(Name in type, Name in type, ...) return 数据类型
is
结果变量 数据类型;
begin
return(结果变量);
end;
存储过程和存储函数的参数都不能带长度
存储函数的返回值类型不能带长度
----通过存储函数实现计算指定员工的年薪
----存储过程和存储函数的参数都不能带长度
----存储函数的返回值类型不能带长度
create or replace function f_yearsal(eno emp.empno%type) return number
is
s number(10);
begin
select sal*12+nvl(comm, 0) into s from emp where empno = eno;
return s;
end;
9. 触发器
触发器类型:
- 语句级触发器 :在指定的操作语句操作之前或之后执行一次,不管这条语句影响了多少行 。
- 行级触发器 (FOR EACH ROW) :触发语句作用的每一条记录都被触发。在行级触发器中使用 old 和 new 伪记录变量, 识别值的状态。
语法
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(条件) ] ]
begin
PLSQL 块
End 触发器名
语句级触发器
----插入一条记录,输出一个新员工入职
create or replace trigger t1
after
insert
on person
declare
begin
dbms_output.put_line('一个新员工入职');
end;
---触发t1
insert into person values (1, '小红');
commit;
select * from person;
行级别触发器
---不能给员工降薪
---raise_application_error(-20001~-20999之间, '错误提示信息');
create or replace trigger t2
before
update
on emp
for each row
declare
begin
if :old.sal>:new.sal then
raise_application_error(-20001, '不能给员工降薪');
end if;
end;
----触发t2
select * from emp where empno = 7788;
update emp set sal=sal-1 where empno = 7788;
commit;
触发器实现主键自增
----触发器实现主键自增。【行级触发器】
---分析:在用户做插入操作的之前,拿到即将插入的数据,
------给该数据中的主键列赋值。
create or replace trigger auid
before
insert
on person
for each row
declare
begin
select s_person.nextval into :new.pid from dual;
end;
--查询person表数据
select * from person;
---使用auid实现主键自增
insert into person (pname) values ('a');
commit;
insert into person values (1, 'b');
commit;