Oracle基础教程文档~超级全
Oracle文档
基础知识
关于数据库语言的分类
DDL:数据库定义语言:create、drop
DML:数据库的操作语言:insert、update、delete
DQL:数据库的查询语言:select
DCL:数据库的控制语言:grant、revoke
数据类型
VARCHAR2(size)
可变长字符数据。VARCHAR2(n)数据类型用于定义可变长度的字符串,其中,n用于指定字符串的最大长度,n的值必须是正整数且不超过32767。
CHAR(size)
定长字符数据。CHAR(n)数据类型用于定义固定长度的字符串,其中,n用于指定字符串的最大长度,n的值必须是正整数且不超过32767。
NUMBER(p,s)
可变长数值数据。NUMBER(precision,scale)数据类型用于定义固定长度的整数和浮点数,其中,precision表示精度,用于指定数字的总位数;scale表示标度,用于指定小数点后的数字位数,默认值为0,即没有小数位数。
DATE
日期型数据。DATE数据类型用于定义日期时间类型的数据,分别描述年、月、日、时、分、秒。
TIMESTAMP
TIMESTAMP数据类型也用于定义日期时间数据,但与DATE仅显示日期不同,TIMESTAMP类型数据还可以显示时间和上下午标记,如“11-9月-2007 11:09:32.213 AM”。
LONG
可变长字符数据,最大可达到2G。LONG数据类型在其它的数据库系统中常被称为备注类型,它主要用于存储大量的可以在稍后返回的文本内容。
CLOB
字符数据,最大可达到4G。
BLOB
二进制数据,最大可达到4G。
ROWID
行地址,十六进制串,表示行在所在的表中唯一的行地址,该数据类型主要用于返回ROWID伪列,常用在可以将表中的每一条记录都加以唯一标识的场合。
提交回滚
在每次执行完数据变更的语句(insert\update\delete)后,需要提交数据
可以将执行数据变更的语句后跟上commit,进行提交
注意:执行变更数据(执行提交)之前,已经要检查语句,是否变更逻辑正确。
别名
as
SELECT count(1) as sjl FROM test1;SELECT t.name FROM test1 as t;
sjl就是count(1)的别名
别名是为了方便计算和防止
通配符
‘%’(百分号): 用来表示任意数量的字符,或者可能根本没有字符。
‘_’(下划线): 表示确切的未知字符。
‘?’(问号): 用来表示确切的未知字符。
‘#’(井号): 用来表示确切的阿拉伯数字,0到9。
‘[a-d]’(方括号):用来表示字符范围,在这里是从a到d。
用户和表空间
创建新用户
CREATE USER usename IDENTIFIED BY password;
授权
GRANT CONNECT, RESOURCE, DBA TO usename;
DBA: 拥有全部特权,是系统最高权限,只有DBA才可以创建数据库结构。
RESOURCE:拥有Resource权限的用户只可以创建实体,不可以创建数据库结构。
CONNECT:拥有Connect权限的用户只可以登录Oracle,不可以创建实体,不可以创建数据库结构。
创建表空间
CREATE TABLESPACE spacename DATAFILE '表空间文件存放路径' SIZE 表空间大小 AUTOEXTEND ON;
-- 例
CREATE TABLESPACE dragon DATAFILE 'C:\Tablespace\dragon.dbf' SIZE 1000M AUTOEXTEND ON;
表和视图
创建表
CREATE
CREATE TABLE tablename(
num1 varchar2(200) null,
num2 varchar2(200) null,
num3 number(10,0) null,
num4 DATE null
)
tablespace spacename -- 指定表空间
comment on table tablename is '表注释';
comment on column tablename.num1 is '字段注释';
tablename:表名
num:字段名
create table test1 (
id varchar2(10) primary key,
name varchar2(200) not null,
phone varchar2(11) null,
adress varchar2(200) null
)
primary key:主键,主键的特性,不能重复且不为空
查询
SELECT
查询
-- 全字段显示
SELECT * FROM tablename;
SELECT num1,num2,num3,num4 FROM tablename;
-- 查询单一字段
SELECT num1 FROM tablename;
-- 查询多个字段
SELECT rowid,num1,num2 FROM tablename;
插入
INSERT INTO
插入
-- 全字段插入
INSERT INTO tablename(num1,num2,num3,num4)VALUES('10001','AT',20,'2022-04-03 00:00:00');
-- 指定字段插入
INSERT INTO tablename(num1,num2)VALUES('10001','AT');
更新
UPDATE
-- 全量更新
UPDATE tablename SET num2 = 'AG';
-- 条件更新
UPDATE tablename SET num2 = 'AG' WHERE num2 = 'AT';
UPDATE tablename SET num2 = 'AG' WHERE num1 = '10001';
FOR UPDATE
SELECT * FROM test1 FOR UPDATE;
*,rowid
SELECT t.*,t.rowid FROM test1 t;
删除表
DELETE
删除数据
-- 全量删除
-- 注1:delete只会删除数据,不会删表
-- 注2:delete删除数据可以回滚
-- 注3:如表数据量大,delete全量删除慢
DELETE FROM tablename;
-- 条件删除
DELETE FROM tablename WHERE num1 = '10001';
DROP
删除表
-- 注:无法回滚
-- 执行前请注意
DROP TABLE tablename;
TRUNCATE
清空表
-- 注:无法回滚
-- 执行速度极快
TRUNCATE TABLE tablename;
创建视图
视图(view),也称虚表, 不占用物理空间,这个也是相对概念,因为视图本身的定义语句还是要存储在数据字典里的。视图只有逻辑定义。每次使用的时候,只是重新执行SQL。
视图是从一个或多个实际表中获得的,这些表的数据存放在数据库中。那些用于产生视图的表叫做该视图的基表。一个视图也可以从另一个视图中产生。
CREATE [OR REPLACE] VIEW v_test1 AS
select t.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t inner join test2 e on t.name = e.name;
语法:
create [or replace] [force] view view_name[(column1,column2,...)]as select ...[ with read only ];
- or replace: 如果存在同名的视图, 则使用新视图"替代"已有的视图
- force: "强制"创建视图,不考虑基表是否存在,也不考虑是否具有使用基表的权限
- with read only:创建的视图只能用于查询数据, 而不能用于更改数据.
视图的作用
- 提供各种数据表现形式, 可以使用各种不同的方式将基表的数据展现在用户面前, 以便符合用户的使用习惯(主要手段: 使用别名);
- 隐藏数据的逻辑复杂性并简化查询语句, 多表查询语句一般是比较复杂的, 而且用户需要了解表之间的关系, 否则容易写错; 如果基于这样的查询语句创建一个视图, 用户就可以直接对这个视图进行"简单查询"而获得结果. 这样就隐藏了数据的复杂性并简化了查询语句.这也是oracle提供各种"数据字典视图"的原因之一,all_constraints就是一个含有2个子查询并连接了9个表的视图(在catalog.sql中定义);
- 执行某些必须使用视图的查询. 某些查询必须借助视图的帮助才能完成. 比如, 有些查询需要连接一个分组统计后的表和另一表, 这时就可以先基于分组统计的结果创建一个视图, 然后在查询中连接这个视图和另一个表就可以了;
- 提供某些安全性保证. 不会让对方看到表结构,视图提供了一种可以控制的方式, 即可以让不同的用户看见不同的列, 而不允许访问那些敏感的列, 这样就可以保证敏感数据不被用户看见;
- 简化用户权限的管理. 可以将视图的权限授予用户, 而不必将基表中某些列的权限授予用户, 这样就简化了用户权限的定义。
条件过滤
WHERE
指定过滤的条件返回符合查询条件的行记录
SELECT * FROM tablename where num2 = 'AB';
num1 | num2 |
---|---|
10001 | AB |
10001 | AB |
AND
并且
-- 查询无结果
SELECT * FROM tablename WHERE num2 = 'AB' AND num2 = 'AC'
SELECT * FROM tablename WHERE num2 = 'AC' AND num2 = '10002'
num1 | num2 |
---|---|
10002 | AC |
OR
或者
SELECT * FROM tablename WHERE num2 = 'AB' OR num2 = 'AC'
Fetch
-- 获取前10行的数据
SELECT * FROM test1 fetch next 10 rows only;
SELECT * FROM test1 fetch first 10 rows only;
SELECT * FROM test1 fetch next 10 rows with ties;-- 获取整表前10%的数据
SELECT * FROM test1 fetch next 10 percent rows only;
OFFSET
-- 获取10行之后的数据
SELECT * FROM test1 offset 10 rows
IN
等于值列表中的任何值
SELECT * FROM tablename WHERE num1 in ('10001','10002');
num1 | num2 |
---|---|
10001 | AB |
10001 | AB |
10002 | AC |
BETWEEN AND
两者之间
SELECT * FROM tablename WHERE num1 BETWEEN 10001 AND 10002;
-- 结果同上
-- 结果等同于num1 >= ’10001‘ and num1 <= ’10002‘
LIKE
模糊查询
-- 以B结尾
SELECT * FROM tablename WHERE num2 LIKE '%B';
-- 以A开头
SELECT * FROM tablename WHERE num2 LIKE 'A%';
-- 包含C的
SELECT * FROM tablename WHERE num2 LIKE '%C%';
CASE WHEN
条件判断
SELECT name,case when sex = '1' then '男' when sex = '0' then '女' end 性别 FROM test6;
分组聚合
group by
分组函数,根据by后面的一定的规则进行分组
count()
计算数据量
count(*)
聚合计算时,包含了所有列,相当于行数,不会忽略NULL值
count(1)
在聚合计算时,忽略所有列,用数字1代表代码行,不会忽略NULL值
count(列名)
在聚合计算时,会忽略列为空(NULL)的值,只算有值的行数
注:在对表作分析计算时,使用count(1)比count(*)用时要少,不过相差不大、
如果表中存在主键,count(主键)效率最高,如果表中只有一列(非主键),则count(*)效率最高,如果表中有多列,则count(1)效率最高
所有执行,相差不大
MAX()
最大
MIN()
最小
SUM()
求和
AVG()
平均值
having
通常用在聚合函数前面,对聚合函数进行筛选
order by
排序
SELECT * FROM test1 ORDER BY id;
SELECT * FROM test1 ORDER BY id ASC;
SELECT * FROM test1 ORDER BY id DESC;
注:
- order by 默认正序排列
- asc 正序排列
- desc 倒序排列
聚合函数注意事项
- where条件后面不能跟聚合函数
- where、group by 、having、order by可以组合使用(例:select name,count(1) as sl from test1 where id is not null group by name having count(1) > 1 order by sl)
- 执行的优先顺序为:where > group by > having > order by
函数
字符串处理函数
LENGTH(S)
计算字符串S长度
LOWER(S)
S转换成小写
UPPER(S)
S转换成大写
CONCAT(X,Y)
连接字符串X和Y
INSTR(X,S,A)
从X中查找S,可以指定从A开始
LTRIM(X,T)
把X的左边截去T字符串,缺省截去空格
RTRIM(X,T)
把X的右边截去T字符串,缺省截去空格
TRIM([T FROM]X)
把X的两边截去T字符串,缺省截去空格
REPLACE(X,O,N)
在X中查找O,并替换成N
SUBSTR(X,start[,length])
返回X的字串,从start处开始,截取length个字符,缺省length,默认到结尾
数值处理函数
ROUND()
四舍五入
TRUNC()
直接截取,不四舍五入。
时间函数
sysdate
返回当前日期
current_date
返回当前时区中的当前日期
add_months(d,m)
增加月份,返回在日期d基础上再加m个月后新的日期。
last_day(d)
返回日期d所在月份最后一天的日期。
months_between(d1,d2)
返回日期d1到日期d2之间的月数。
trunc(d,[c])
返回日期d1所在期间(参数c,年月周范围)的第一天日期
SELECT sysdate,trunc(sysdate,'year'),trunc(sysdate,'month'),trunc(sysdate,'day') FROM test;
-- 结果 2022-04-05 2022-01-01(本年第一天) 2022-04-01(本月第一天) 2022-04-03(本周第一天)
next_day(d,[c])
返回日期d在下周,星期几(参数c)的日期
SELECT sysdate,next_day(sysdate,'星期一') FROM test3
-- 结果为下周一的日期
类型转换函数
TO_DATE
将字符串转换为时间类型
SELECT to_date('2022-04-05 19:20:00','yyyy-MM-dd hh24:mi:ss') FROM test;
TO_CHAR
将数值、时间等格式转换为字符串类型
SELECT to_char(sysdate,'yyyy-MM-dd hh24:mi:ss') FROM test;
TO_NUMBER
将字符串转换为数值类型
SELECT to_number('9999999','$999,999,999') FROM test;
注:
- 当char类型转换date类型时需要用到to_date函数,
- 当date类型转换char类型时需要用到to_char函数
- 当char类型转换number类型时需要用到to_number函数
- 当number类型转换char类型时需要用到to_char函数
分析函数和开窗函数
开窗函数指定了函数所能影响的窗口范围,也就是说在这个窗口范围中都可以受到函数的影响
与聚合函数的区别:
普通的聚合函数用group by分组,每个分组返回一个统计值,而分析函数采用partition by分组,并且每组每行都可以返回一个统计值。
over()
- 用于标识分析函数
- over关键字后的括号中的选项为空,则开窗函数会对结果集中的所有行进行聚合运算
- over关键字后的括号中的选项为不为空,则按照括号中的范围进行聚合运算
row_number()over()
从1开始,为每一条分组记录返回一个数字
SELECT id,row_number()over(order by id desc) rn FROM test1
row_number()over(partition by order by )
SELECT name,cxxx,gxsj,row_number()over(partition by name order by gxsj desc) rn FROM test5
partition by:分区子句,根据分区表达式的条件逻辑将单个结果集进行分组
order by:排序子句,用于对分区中的数据进行排序
count(*)over()
查询结果的每一行都返回所有符合条件行的条数
SELECT id,name,phone,count(*)over() FROM test1 WHERE name = '猪八戒'
sum()over()
SELECT id,name,sum(phone)over() FROM test1;
range
用来指定时间范围进行统计
SELECT id,name,sum(phone)over(order by phone range between unbounded preceding and current row) FROM test1;
-- 查询从第一行到当前行的手机号总和
unbounded preceding:包含当前行之前的所有行
current row:当前行
rank( )
返回一个唯一的值,当碰到相同的数据时,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名
SELECT id,name,rank()over(order by name) FROM test1;
dense_rank( )
返回一个唯一的值,当碰到相同数据时,此时所有相同数据的排名都是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间紧邻递增。
SELECT id,name,dense_rank()over(order by name) FROM test1;
其他函数
DISTINCT
去掉多余的重复记录
NVL(X,VALUE)
空值处理,当x值为空,则返回value
NVL2(x,value1,value2)
空值条件返回,当x值为空,则返回value1,否则则返回value2
EXISTS
在oracle中,exists的作用就是检查子查询的结果是否为真,如果子查询为true则执行外面的SQL语句,如果返回为false则不执行外面的SQL语句,语法为“select * from daul where exists(条件)”。
子查询
SELECT * FROM (SELECT name,count(1) as sjl FROM test1 GROUP BY name)
SELECT name,city,salary,(SELECT count(salary) FROM student WHERE salary < 4000) FROM student WHERE salary < 4000
关联
left join
左联接:结果包括左表(出现在JOIN子句最左边)中的所有行,不包括右表中的不匹配行。
select t.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t left join test2 e on t.name = e.name
right join/right outer join
右联接:结果包括右表(出现在JOIN子句最右边)中的所有行,不包括有左表中的不匹配的行。
select e.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t right join test2 e on t.name = e.name
inner join/inner outer join
内联接,结果为两个联接表中的匹配行的联接
select t.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t inner join test2 e on t.name = e.name
full join/full outer join
全联接:结果包括所有联接中的所有行,不论他们是否匹配。
select t.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t full join test2 e on t.name = e.name
except
EXCEPT 返回两个结果集的差(即从左查询中返回右查询没有找到的所有非重复值)。
intersect
INTERSECT 返回 两个结果集的交集(即两个查询都返回的所有非重复值)。
交叉关联
生成笛卡尔积——直接将一个数据源中的每个行和另一个数据源中的每个行,一一匹配
SELECT a.name,b.name FROM test1 a,test2 b
(+)
在oracle数据库中 (+)是一种特殊用法,表示外连接,(+)放在那一边,就标识,那边可以为空
/*此SQL相当于左关联*/
select t.name,t.phone,t.adress,e.wq,e.sf,e.zx from test1 t,test2 e where t.name = e.name(+)
集合操作符
union
不包含重复值,默认按第一个查询的第一列升序排列。
select t.id,t.name from test1 t union select e.id,e.name from test2 e
union all
完全并集包含重复值。不排序。
select t.id,t.name from test1 t union all select e.id,e.name from test2 e
minus
不包含重复值,不排序。
索引约束(索引理论)
概念
**Oracle索引(index)最大的作用是用来优化数据库查询的效率,提升数据库的查询性能。**就好比书的目录一样,可以通过目录来直接定位所需内容存在的页数,大大提高检索效率。
Oracle数据库中如果某列出现在查询的条件中,而该列的数据是无序的,查询时只能从第一行开始一行一行的匹配。创建索引就是对某些特定列中的数据进行排序或归类,生成独立的索引表。在某列上创建索引后,如果该列出现在查询条件中,Oracle 会自动的引用该索引,先从索引表中查询出符合条件记录的 ROWID,由于 ROWID 是记录的物理地址,因此可以根据 ROWID 快速的定位到具体的记录,当表中的数据非常多时,引用索引带来的查询效率非常可观 。
索引创建
创建标准索引:
CREATE INDEX 索引名 ON 表名 (列名) TABLESPACE 表空间名;
创建唯一索引:
CREATE unique INDEX 索引名 ON 表名 (列名) TABLESPACE 表空间名;
创建位图索引:
CREATE bitmap INDEX 索引名 ON 表名(列名) 表空间
创建组合索引:
CREATE INDEX 索引名 ON 表名 (列名1,列名2) TABLESPACE 表空间名;
创建反向键索引:
CREATE INDEX 索引名 ON 表名 (列名) reverse TABLESPACE 表空间名;
索引操作
给列名增加一个唯一约束
alter table 表名 add constraint 索引名 unique(列名)
删除唯一约束
alter table 表名 drop unique (列名)
删除索引
alter table 表名drop constraint 索引名
drop index 索引名;
禁用和激活索引
alter table 表名 disable/enable unique 唯一约束
alter table 表名 disable/enable constraint 索引名
alter table 表名 modify constraint 唯一约束 disable/enable
alter table 表名 modify constraint 索引名 disable/enable
清理索引碎片
1.合并索引(只是简单的将B树叶结点中的存储碎片合并在一起,并不会改变索引的物理组织结构)
alter index 索引名 coalesce;
2.重建索引(不仅能够消除存储碎片,还可以改变索引的全部存储参数设置,并且可以将索引移动到其它的表空间中,重建索引
实际上就是再指定的表空间中重新建立一个新的索引,然后删除原来的索引)
alter index 索引名 rebuild;
索引的类别
1、b-tree索引:Oracle数据中最常见的索引,就是b-tree索引,create index创建的normal就是b-tree索引,没有特殊的必须应用在哪些数据上。
2、bitmap位图索引:位图索引经常应用于列数据只有几个枚举值的情况,比如上面说到过的性别字段,或者我们经常开发中应用的代码字段。这个时候使用bitmap位图索引,查询效率将会最快。
3、函数索引:比如经常对某个字段做查询的时候经常是带函数操作的,那么此时建一个函数索引就有价值了。例如:trim(列名)或者substr(列名)等等字符串操作函数,这个时候可以建立函数索引来提升这种查询效率。
4、hash索引:hash索引可能是访问数据库中数据的最快方法,但它也有自身的缺点。创建hash索引必须使用hash集群,相当于定义了一个hash集群键,通过这个集群键来告诉oracle来存储表。因此,需要在创建HASH集群的时候指定这个值。存储数据时,所有相关集群键的行都存储在一个数据块当中,所以只要定位到hash键,就能快速定位查询到数据的物理位置。
5、reverse反向索引:这个索引不经常使用到,但是在特定的情况下,是使用该索引可以达到意想不到的效果。如:某一列的值为{10000,10001,10021,10121,11000,…},假如通过b-tree索引,大部分都密集分布在某一个叶子节点上,但是通过反向处理后的值将变成{00001,10001,12001,12101,00011,…},很明显的发现他们的值变得比较随机,可以比较平均的分部在各个叶子节点上,而不是之前全部集中在某一个叶子节点上,这样子就可大大提高检索的效率。
6、分区索引和分区表的全局索引:这两个索引是应用在分区表上面的,前者的分区索引是对分区表内的单个分区进行数据索引,后者是对分区表的全表进行全局索引。分区表的介绍,可以后期再做单独详解,这里就不累述了。
索引使用原则
索引字段建议建立NOT NULL约束
经常与其他表进行连接的表,在连接字段上应该建立索引;
经常出现在Where子句中的字段且过滤性很强的,特别是大表的字段,应该建立索引;
复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:
A、正确选择复合索引中的第一个字段,一般是选择性较好的且在where子句中常用的字段上;
B、复合索引的几个字段经常同时以AND方式出现在Where子句中可以建立复合索引;否则单字段索引;
C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;
D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;
E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;
频繁DML的表,不要建立太多的索引;
不要将那些频繁修改的列作为索引列;
索引失效
- .没有where条件或者条件中的列不是索引列
众所周知,添加索引的字段必需要在where条件后适当使用才会生效,如果连查询条件都没有,那肯定不会用到索引的。 - 使用 IS NULL 和 IS NOT NULL
select … from emp where colnum is null; colnum列的索引会失效 - WHERE 子句中使用函数
如果没有使用基于函数的索引,那么 where 子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。例如:
select * from staff where trunc(birthdate) = ‘01-MAY-82’;
但是把函数应用在条件上,索引是可以生效的,把上面的语句改成下面的语句,就可以通过索引进行查找。
select * from staff where birthdate < (to_date(‘01-MAY-82’) + 0.9999);
注意:对于 MIN, MAX 函数,Oracle 仍然使用索引。 - 使用 LIKE ‘%T’ 进行模糊查询
select * from student where name like ‘aaa%’ ; // ‘aaa%’ 会用到索引
select * from student where name like ‘%aaa’ ; //’%aaa’ 或者 ‘_aaa’ 不会使用索引 - WHERE 子句中使用不等于操作
不等于操作包括:<>, !=, NOT colum >= ?, NOT colum <= ?
对于这个限制条件可以通过 OR 替代,例如: colum <> 0 ===> colum>0 OR colum<0 - 等于和范围索引不会被合并使用
SELECT emp_id, emp_m, salary_q … FROM emp WHERE job=‘manager’ AND deptno>10
job 和 deptno 都是非唯一索引,这种条件下 oracle 不会合并索引,它只会使用第一个索引。 - 比较不匹配数据类型
dept_id是一个varchar2型的字段,在这个字段上有索引,但是下面的语句会执行全表扫描。
select * from temp where dept_id = 100101;
这是因为 oracle 会自动把 where 子句转换成 to_number(dept_id)=900198,相当于使用函数,这样就限制了索引的使用。正确写法如下:
select * from temp where dept_id = ‘100101’;
索引的优缺点
优点:
- 创建唯一性索引,保证数据库表中每一行数据的唯一性
- 大大加快数据的检索速度,这也是创建索引的最主要的原因
- 加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
- 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
缺点:
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
- 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度
事务(ACID)
- 原子性(Atomicity):一个事务里面所有包含的SQL语句都是一个整体,是不可分割的,要么不做,要么都做。
- 一致性(Consistency):事务开始时,数据库中的数据是一致的,事务结束时,数据库的数据也应该是一致的。
- 隔离性(Isolation):数据库允许多个并发事务同时对其中的数据进行读写和修改的能力,隔离性可以防止事务在并发执行时,由于他们的操作命令交叉执行而导致的数据不一致状态。
- 持久性 (Durability) :当事务结束后,它对数据库中的影响是永久的,即便系统遇到故障的情况下,数据也不会丢失。
一组SQL语句操作要成为事务,数据库管理系统必须保证这组操作的原子性(Atomicity)、一致性(consistency)、隔离性(Isolation)和持久性(Durability),这就是ACID特性。
事务控制语句
commit;提交
rollback;回滚
事务的过程
事务开始于:
DDL语句的执行
事务结束于:
commit;或rollback;
用户退出数据库(正常退出则会后台运行完提交,不正常退出则会回滚)
系统崩溃(回滚)
事务锁
DDL锁:保护数据库对象结构(表、索引)的完整性
DML锁:保护数据的完整性
对某表进行DML语句执行的过程中,会对该表进行DDL锁。
DDL锁是为了防止在事务结束之前,其他用户对该表进行DDL操作
对某表进行DDL语句执行的过程中,会对该表进行DML锁。
DML锁是为了在修改表结构时,其他用户会对该表进行DML操作
DML锁:表级锁™、行锁(TX)
TM锁,面向对象,并且锁定了数据库中的一个对象(表),在锁定期间中,不允许对该对象进行DDL操作
TX锁,面向事务,表示锁定了数据库中的一个事务。
当update语句执行时,Oracle优先申请TM锁,然后在申请TX锁,并标定数据行锁的位置
锁表
锁表的概念;
- A程序执行了对 tableA 的 insert ,并还未 commite时,B程序也对tableA 进行insert 则此时会发生资源正忙的异常 就是锁表;
- 锁表常发生于并发而不是并行
减少锁表的概率:
- 减少insert 、update 、delete 语句执行 到 commite 之间的时间。具体点批量执行改为单个执行、优化sql自身的非执行速度;
- 如果异常对事物进行回滚
死锁:
两个事务更新同一个表,并且同时每个事务要更新的数据正在被另外一个事务所锁定。因为两个事务在相互等待资源,两个事务都无法继续下去直到ORACLE产生一个DEADLOCK的错误。
查询锁表:
select s.username,l.object_id, l.session_id,s.serial#, s.lockwait,s.status,s.machine,s.program from v s e s s i o n s , v session s,v sessions,vlocked_object l where s.sid = l.session_id;
杀进程:
alter system kill session ‘301,16405’;
PL/SQL(程序SQL语言)
变量
变量类型
普通变量类型(char、varchar2、date、number、boolean、long、integer)
特殊变量类型 (引用型变量、记录型变量)
变量声明方式
变量名 变量类型(长度)
name varchar2(20);
普通变量赋值
- 直接赋值 :=
- 语句赋值 select … into …
输出示例
DECLARE-- 姓名name varchar2(20) := '张三'; -- 声明变量直接赋值-- 薪水sal number;-- 地址address varchar2(200);
BEGIN-- 薪水直接赋值sal := 5000;-- 地址语句赋值SELECT '北京市长安大街' INTO address FROM dual;-- 输出dbms_output.put_line('姓名:'||name||' 薪水:'||sal||' 地址:'||address)
END;
引用型变量赋值
变量的类型和长度取决于表中字段的类型和长度
通过表名.列名%TYPE指定变量的类型和长度
p_name test.name%TYPE;
输出示例
DECLARE-- 姓名c_name test.name%TYPE := '张三'; -- 声明变量直接赋值-- 手机c_phone test.phone%TYPE;
BEGIN-- 语句赋值SELECT phone into c_phone FROM test WHERE id = '10001';-- 输出dbms_output.put_line('姓名:'||c_name||' 手机:'||c_phone)
END;
记录型变量赋值
接收表中的一整行数据记录
如果表里边需要引用的字段过多,可以用记录型变量解决复杂操作的问题
变量名称 表名%ROWTYPE
c_test test%ROWTYPE
输出示例
DECLAREc_test test%ROWTYPE;BEGIN-- 语句赋值SELECT * into c_test FROM test WHERE id = '10001';-- 输出dbms_output.put_line('姓名:'||c_test.c_name||' 手机:'||c_test.c_phone)
END;
流程控制
条件分支
语法
BEGINIF 条件1 THEN 执行1ELSEIF 条件2 THEN 执行2ELSE 执行3END IF;
END;
输出示例
DECLAREv_count integer;
BEGIN-- 语句赋值SELECT count(1) into v_count FROM test;IF v_count > 20 THEN dbms_output.put_line('test表中的记录数超过了20条,记录数是:'||v_count);ELSEIF v_count>=10 THEN dbms_output.put_line('test表中的记录数在10-20条,记录数是:'||v_count);ELSE dbms_output.put_line('test表中的记录数在10条以下,记录数是:'||v_count);END IF;
END;
循环
LOOP循环
语法
BEGINLOOPEXIT WHEN -- 退出循环条件END LOOP;
END;
输出示例
DECLAREv_num integer := 1;
BEGINLOOPEXIT WHEN v_num > 10-- 输出dbms_output.put_line(v_num);v_num := v_num + 1;END LOOP;
END;
WHILE循环
DECLAREi number;
BEGINi:=0;WHILE i<5 LOOPi:=i+1;dbms_output.put_line(i);END LOOP;
END;
FOR循环
DECLAREi number;
BEGINi:=0;FOR i IN 1..5 LOOPdbms_output.put_line(i);END LOOP;
END;
DECLAREuserRow t_user%rowtype;cursor userRows is select * from t_user;
BEGINFOR userRow IN userRows LOOPdbms_output.put_line(userRow.Id||','||userRow.Name||','||userRows%rowcount);END LOOP;
END;
游标
概念
用于临时存储一个查询返回的多行数据的结果集,通过遍历游标,可以逐行访问处理该结果集的数据
游标使用方式:声明—打开—读取—关闭
语法
CURSOR 游标名[(游标参数)] IS 查询语句 -- 声明游标
OPEN 游标名; -- 打开游标
FETCH 游标名 INTO 变量列表; -- 游标取值
CLOSE 游标名; -- 关闭游标
游标的属性
属性 | 返回值类型 | 说明 |
---|---|---|
%ROWCOUNT | 整型 | 获取FETCH语句的数据行数 |
%FOUND | 布尔型 | 最近的FETCH语句的返回一行数据则为真,否则为假 |
%NOTFOUND | 布尔型 | 与%FOUND相反 |
%ISOPEN | 布尔型 | 游标已经打开为真,否则为假 |
输出示例
DECLARECURSOR v_csr IS SELECT name,phone FROM TEST;v_name test.name%TYPE;v_phone test.phone%TYPE;
BEGINOPEN v_csr;LOOP --遍历游标FETCH v_csr INTO v_name,v_phone; --获取游标中的数据EXIT WHEN v_csr%NOTFOUND; -- 退出循环条件dbms_output.put_line(v_name||','||v_phone);END LOOP;CLOSE v_csr;
END;
带参游标
为游标添加参数(类似形参)
输出示例
DECLARECURSOR v_csr(v_id test.id%TYPE) IS SELECT name,phone FROM TEST WHERE id = v_id;v_name test.name%TYPE;v_phone test.phone%TYPE;
BEGINOPEN v_csr(10001);LOOP --遍历游标FETCH v_csr INTO v_name,v_phone; --获取游标中的数据EXIT WHEN v_csr%NOTFOUND; -- 退出循环条件dbms_output.put_line(v_name||','||v_phone);END LOOP;CLOSE v_csr;
END;
注意:循环中(LOOP
之后)要加上FETCH
,否则在利用EXIT WHEN v_csr%NOTFOUND
进行判断时,会默认它有值,然后在执行FETCH
后,会带着FETCH
之后的结果,进入循环,造成多输出最后一条数据
EXECUTE IMMEDIATE
在PL/SQL中,是可以直接执行DML语句的,同时也可以用execute immediate ‘sql’ 去执行SQL语句
利用execute去执行DML或者DDL语句是比较灵活的,因为它可以执行动态的SQL语句。
DECLAREv_sql VARCHAR2(200);v_sname stu_info.sname%TYPE;v_num PLS_INTEGER;
BEGIN-- 用法1 : ddl 语句v_sql := 'create or replace view vw_stu_info as select sno, sname from stu_info';EXECUTE IMMEDIATE v_sql;-- 用法2 :dml 语句 + 动态 sqlv_sql := 'insert into stu_info(sno, sname) values(:b1, :b2)';EXECUTE IMMEDIATE v_sqlUSING 3, '倩倩';-- 用法3:赋值给某个变量v_sql := 'select count(1) from stu_info';EXECUTE IMMEDIATE v_sqlINTO v_num;dbms_output.put_line('总记录条数:' || v_num);-- 记得 commit(同 Oracle 语法)COMMIT;
END;
存储过程
概念
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来调用存储过程。
存储过程包含三部分:过程声明,执行过程部分,存储过程异常
创建存储的优点
效率高
存储过程编译一次后,就会存到数据库,每次调用时都直接执行。而普通的sql语句我们要保存到其他地方(例如:记事本 上),都要先分析编译才会执行。所以想对而言存储过程效率更高。
降低网络流量
存储过程编译好会放在数据库,我们在远程调用时,不会传输大量的字符串类型的sql语句。
复用性高
存储过程往往是针对一个特定的功能编写的,当再需要完成这个特定的功能时,可以再次调用该存储过程。
可维护性高
当功能要求发生小的变化时,修改之前的存储过程比较容易,花费精力少。
安全性高
完成某个特定功能的存储过程一般只有特定的用户可以使用,具有使用身份限制,更安全。
创建存储过程
CREATE [OR REPLACE] PROCEDURE 存储过程名称 [(输入参数或输出参数)] IS -- 声明变量和游标-- 如果程序中无声明可省略
BEGIN-- 执行语句-- [异常处理]
END;
执行存储过程方式
- Call 存储过程名称(参数);
- Execute (exec)存储过程名称(参数);
- PL/SQL内执行
注意:
- 在oracle 数据库中,call命令任何窗口都能使用,但是execute只能在命令窗口使用,否则会报无效的SQL语句的异常。
- sqlplus客户端的输出选项默认是关闭的,需要用set serveroutput on来打开
在存储过程中需要注意事项
1、在oracle数据库存储过程中,表别名不能用as
2、在oracle数据库存储过程中,select某一字段时,后面必须紧跟into,如果select整个记录则必须使用游标处理
3、在使用select…into…时必须保证数据库有该数据,否则报”no data found”异常
4、在存储过程中,别名不能和字段名相同,否则虽然编译能通过,但是运行结果会报错
无参存储过程
语法
CREATE OR REPLACE PROCEDURE 过程名称 IS
BEGINEND [过程名称];
注:无DECLARE
声明,IS
后可直接跟上声明
输出示例
CREATE OR REPLACE PROCEDURE p_test IS
BEGIN
dbms_output.put_line('Hello Word');
END [过程名称];
执行示例
call p_test(); -- 所有窗口均可执行
exec p_test; -- 命令窗口执行DECLARE
BEGINp_test();
END;
带参存储过程
语法
CREATE OR REPLACE PROCEDURE 过程名称[(参数列表)]
BEGINEND [过程名称];
输入参数
CREATE OR REPLACE PROCEDURE p_test(p_id IN test.id%TYPE) ISv_name test.name%TYPE;v_phone test.phone%TYPE;
BEGINSELECT name,phone INTO v_name,v_phone FROM test WHERE id = p_iddbms_output.put_line(v_name||','||v_phone);
END;
执行示例
call p_test2('10001');
exec p_test2('10001');DECLARE
BEGINP_TEST('10001');
END;
输出参数
CREATE OR REPLACE PROCEDURE p_test(p_id IN test.id%TYPE,p_name OUT test.name%TYPE) IS
BEGINSELECT name INTO v_name FROM test WHERE id = p_idEND;
执行示例
DECLAREv_name test.name%type; -- 生成一个新的变量去接收存储过程的返回值
BEGINP_TEST('10001',v_name);dbms_output.put_line(v_name);
END;
IN, OUT , IN OUT 用来修饰参数。
IN 表示这个变量必须被调用者赋值然后传入到 PROCEDURE 进行处理。
OUT 表示 PRCEDURE 通过这个变量将值传回给调用者。
IN OUT 则是这两种的组合。
创建函数
语法
create [or replace] function 函数名
([p1,p2...pn])
return datatype
is|as
--声明部分
begin
--PL/SQL程序块
end
函数示例
CREATE OR REPLACE FUNCTION F_MSG(NAME_U IN VARCHAR2,NAME_P IN VARCHAR2
)RETURN NUMBER IS ALL_T NUMBER;BEGIN SELECT SUM(A.PRODUCT_NUM*A.PRICE) INTO ALL_T FROM PRODUCT_RELEASE A,USER_M BWHERE A.USER_ID=B.USER_ID AND B.USER_NAME=NAME_U AND A.PRODUCT_NAME=NAME_PGROUP BY B.USER_NAME,A.PRODUCT_NAME;RETURN ALL_T;END F_MSG;
执行函数的方法
SELECT F_MSG('甲','男人') AS"总额" FROM DUAL;
函数和存储过程的区别
- 可以理解函数是存储过程的一种
- 函数可以没有参数,但是一定需要一个返回值,存储过程可以没有参数,不需要返回值
- 函数return返回值没有返回参数模式,存储过程通过out参数返回值, 如果需要返回多个参数则建议使用存储过程
- 在sql数据操纵语句中只能调用函数而不能调用存储过程
触发器
触发器是在事件发生时隐式地自动运行的PL/SQL程序块,不能接收参数,不能被调用。
语法
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;
- BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。
- FOR EACH ROW选项说明触发器为行触发器。
- 行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。
当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则只能为行触发器。 - REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(
Oracle基础教程文档~超级全相关推荐
- oracle基础知识文档,Oracle 基础知识分享PPT
因测试组需求,所以把Oracle基础知识整理成了PPT,并讲解了一下(PPT无风格,简约派吐舌头). Oracle 是以高级结构化查询语言(SQL)为基础的大型关系数据库,通俗地讲它是用方便逻辑管理的 ...
- php基础教程文档,PHP5基础教程
*/ php5学习笔记 第一节--面向对象编程 面向对象编程被设计来为大型软件项目提供解决方案,尤其是多人合作的项目. 当源代码增长到一万行甚至更多的时候,每一个更动都可能导致不希望的副作用. 这种情 ...
- 阿里云建站教程文档汇总(详细指南)
阿里云建站零基础入门 选择服务器(推荐阿里云ECS) 购买和备案域名(时间比较长,建议购买完服务器就做这一步) 部署网站 解析域名(将域名和自身网站挂钩) 本篇汇总教程为使用阿里云建站的新用户介绍了搭 ...
- Oracle 基础教程
oracle基础教程 目录 1.oracle的安装 2.变量和类型 3.控制语句 4.oracle用户及授权管理 5.管理数据表 6.查询数据表 7.操纵数据表 8.SQL内置函数 9.触发器 10. ...
- rhel6上使用udev配置oracle asm,Red Hat Enterprise Linux 6使用udev配置Oracle ASM总结文档
1.概述 在Red Hat Enterprise Linux (RHEL)6以前,Oracle均是使用ASMLib这个内核支持库配置ASM. ASMLIB是一种基于Linux module,专门为Or ...
- 【转】(六)unity4.6Ugui中文教程文档-------概要-UGUI Animation Integration
原创至上,移步请戳:(六)unity4.6Ugui中文教程文档-------概要-UGUI Animation Integration 5.Animation Integration(动画集成) 动画 ...
- jquery.cookie 使用文档,$.cookie() 文档教程, js 操作 cookie 教程文档。
jquery.cookie 使用文档,$.cookie() 文档教程, js 操作 cookie 教程文档. jquery.cookie中的操作: jquery.cookie.js是一个基于jquer ...
- atitit.微信支付的教程文档 attilax总结
atitit.微信支付的教程文档 attilax总结 1. 支付流程概览 1 2. 设置支付起始目录 host/app/paydir/ 1 3. 设置oauth验证域名 1 4. 测试目录 可以使 ...
- 【转】(五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components
原创至上,移步请戳:(五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components 4.Interaction Components 本节涵盖了处 ...
最新文章
- python dataframe显示网格_python dataframe 输出结果整行显示的方法
- [Web开发] 在网页中动态加入RSS feed 元素
- (学)新版动态表单研发,阶段成果----1
- c++学习之const成员变量与成员函数
- WebService技术详解CXF
- c++中射线表示_射线与球的相交测试
- 30款油漆纹理Photoshop笔刷
- java 导出word 表格里写多行内容_论文Tips || 宅家写论文干货来了!是时候重启真正的论文了!...
- SQL Sever 创建视图
- java 牙位图插件_牙医的骄傲-智能牙位图中文医疗应用app全球排名No.1
- 高清电子警察监控系统方案
- NOIp2014 提高组 Day1 T1 生活大爆炸版石头剪刀布
- 使用Github上传本地项目代码
- php设备巡检管理,设备巡检管理:你必须知道的4个玩法
- java时区时间转换
- HP Gen8 MicroServer win7 系统安装手册(usb)
- 阿里巴巴Java开发手册(部分)-黄山
- 软件设计原则之里氏替换原则、依赖倒置原则
- 屏幕录像制作gif动态图
- 服务器物理架构部署图,部署图
热门文章
- oracle基础知识文档,Oracle 基础知识分享PPT