alin的学习之路(数据库篇:三)(多表查询,子查询,集合运算,数据处理)
alin的学习之路(数据库篇:三)(多表查询,子查询,集合运算,数据处理)
1. 多表查询
1.1 笛卡儿积
笛卡尔积就是两个集合的乘积计算 。
如果多个表进行联合查询, 得到结果是一个笛卡尔积, 举例: 比如有两个表 aaa , bbb
行数: 两个表中行数的乘积
列数: 两个表中列数之和
1.2 等值连接/不等值连接
等值连接和不等值连接的作用: 通过判断过滤多表查询得到的笛卡尔积中的无效数据
等值连接和不等值连接的区别:where后面判断条件使用的符号是 = 还是其他符号
- 等值连接
查询员工信息:员工号,姓名,月薪(在emp表中)和部门名称(在dept表中)
-- from后边可以加多张表, 表名之间使用 ,(逗号) 间隔
-- select 后边的列名, 一般不是直接指定, 而是: 表名.列名
SQL> select e.empno, e.ename, e.sal, d.dname from emp e, dept d where e.deptno=d.deptno;
EMPNO ENAME SAL DNAME
----- -------------------------------------------------- --------- ------------------------------
7840 岸本_齐史 5000.00 周刊少年Jump
7839 尾田_荣一郎 5000.00 周刊少年Jump
7521 娜美 4560.00 草帽海贼团
7566 蒙奇·D·路飞 5450.00 草帽海贼团
7654 妮可·罗宾 5500.00 草帽海贼团
7788 乌索普 3000.00 草帽海贼团
7708 * 3000.00 草帽海贼团
-- 其中emp后面的e,以及dept后面的d,表示表的别名。可以用来修饰列名。
-- 也可以不用别名直接用表名,会显得冗杂
- 不等值连接
- 询员工信息:员工号, 姓名, 月薪 和 月薪级别(salgrade表)
-- 员工号,姓名,月薪在 emp 表中
-- 月薪级别在 salgrade 表中
SQL> select e.empno, e.ename, e.sal from emp e, salgrade s where e.sal between s.losal and s.hisal ;
EMPNO ENAME SAL
----- -------------------------------------------------- ---------
7934 托尼托尼·乔巴 800.68
7876 布鲁克 1100.00
7844 弗兰奇 1500.00
7707 Franky 2000.00
7900 甚平 2000.00
7701 Roronoa Zoro 2000.00
7699 夏奇 2050.00
7782 贝波 2450.00
7703 Usopp 2500.00
- 按部门统计员工人数,显示如下信息:部门号,部门名称,人数
-- 部门号和部门名称在dept表中
-- 人数的统计需要在 emp 表中完成
SQL> select d.deptno, d.dname ,count(e.ename) from dept d, emp e where d.deptno=e.deptno
group by d.deptno, d.dname ;
DEPTNO DNAME COUNT(E.ENAME)
------ ------------------------------ --------------
10 周刊少年Jump 2
40 红发海贼团 5
60 D之一族 8
50 黑胡子海贼团 4
20 草帽海贼团 19
30 红心海贼团 7
6 rows selected
上述结果中是没有将 45 号部门统计到查询的结果集中的, 应该如何也将其统计到结果集中?
因为45号部门在emp表中没有该部门的成员,所以45号部门并未统计进入该查询。如果想要显示45号部门,需要使用外连接。
1.3 外连接
使用select, 在最后的查询结果中,如果想要包含某些对于where条件来说不成立的记录 , 我们可以使用外
连接. 外连接分为 左外连接 和 右外连接 .
在左连接和右连接时都会以一张A表为基础表,该表的内容会全部显示,然后加上A表和B表匹配的内
容。 如果A表的数据在B表中没有记录。 那么在相关联的结果集行中列显示为空值(NULL)。
对于外连接, 可以使用“(+) ”来表示。 关于使用(+)的一些注意事项:
- (+)操作符只能出现在WHERE子句中。
- 当使用(+)操作符执行外连接时,如果在WHERE子句中包含有多个条件,则必须在所有条件
中都包含(+)操作符。- (+)操作符只适用于列,而不能用在表达式上。
- (+)操作符不能与 OR 和 IN 操作符一起使用。
- (+)操作符只能用于实现左外连接和右外连接,而不能用于实现完全外连接。
通过 (+) 就可以对查询的结果进行补充, 补充不满足条件的那一方
举例: where e.deptno = d.deptno
在d表中 有45 这个部门, 也就是 d.deptno 有可能 等于45
在表 e中没有45号部门的员工, 因此 e.deptno 绝对不会等于45
使用 (+) 就可以对不满足条件的结果进行补充, 根据上述的描述 e.deptno 是需要补充的,
因此将 (+) 写到 e.deptno 后边就可以
where e.deptno(+) = d.deptno , 要补充的是数据来自于等号右侧的 d.deptno
这样当 d.deptno=45 的时候 where e.deptno = d.deptno 这个条件成立
- 左外连接(左边的表不加限制)
用(+)来实现, 这个+号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配
表。如果加号写在右表,左表就是全部显示,所以是左连接。
通俗理解:哪个表少数据了,就在哪个表的那一端加上(+)
-- 再回到刚才的问题,如果想要在查询中也显示出45号部门的员工人数,则需要使用外连接
SQL> select d.deptno, d.dname ,count(e.ename) from dept d, emp e where d.deptno=e.deptno(+)
group by d.deptno, d.dname ;
DEPTNO DNAME COUNT(E.ENAME)
------ ------------------------------ --------------
10 周刊少年Jump 2
40 红发海贼团 5
45 黑桃海贼团 0
60 D之一族 8
50 黑胡子海贼团 4
20 草帽海贼团 19
30 红心海贼团 7
7 rows selected
- 右外连接(右边的表不加限制)
用(+)来实现, 这个+号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配
表。如果加号写在左表,右表就是全部显示,所以是右连接。
SQL> select d.deptno, d.dname ,count(e.ename) from dept d, emp e where e.deptno(+)=d.deptno
group by d.deptno, d.dname ;
DEPTNO DNAME COUNT(E.ENAME)
------ ------------------------------ --------------
10 周刊少年Jump 2
40 红发海贼团 5
45 黑桃海贼团 0
60 D之一族 8
50 黑胡子海贼团 4
20 草帽海贼团 19
30 红心海贼团 7
7 rows selected
-- 以上结果和左外连接相同,只是sql语句的书写方式不同
1.4 自连接
自连接: 通过给当前表设置不同的别名,将同一张表视为多张表来使用, 进行多表联查。(也就是自己和自己对比)
举例: 查询 xxx员工的老板是 yyy, 最后将尾田/岸本的老板也显示出来
-- emp 表中有一个字段叫做 mgr ,存放的是员工的老板数据,只要取出mgr中的数据对应到emp表中查询即可完成查询
SQL> select e.ename "员工", b.ename "老板" from emp e, emp b where e.mgr=b.empno;
-- 使用这一条语句可以发现结果中少了两个记录,因为尾田/岸本在表中没有老板,所以没有显示,这个时候要加上自连接
SQL> select e.ename "员工", b.ename "老板" from emp e, emp b where e.mgr=b.empno(+);
-- 自连接的理念和外连接一样,哪端的数据少就在哪端加(+),b表中缺少数据,所以在b表一端加上(+)
员工 老板
-------------------------------------------------- --------------------------------------------------
阿巴罗·皮萨罗 马歇尔·D·帝奇
芝沙斯·巴沙斯 马歇尔·D·帝奇
岸本_齐史
尾田_荣一郎
45 rows selected
-- 如果要想给尾田/岸本在查询后增加个显示,需要再搭配nvl使用
SQL> select e.ename "员工", nvl(b.ename,'他老婆') "老板" from emp e, emp b where e.mgr=b.empno(+);
员工 老板
-------------------------------------------------- --------------------------------------------------
阿巴罗·皮萨罗 马歇尔·D·帝奇
芝沙斯·巴沙斯 马歇尔·D·帝奇
岸本_齐史 他老婆
尾田_荣一郎 他老婆
45 rows selected
2. 子查询
子查询就是select 语句的嵌套使用, 即: 在select中使用select。 表示子语句的select需要写在()中
写到()中的select执行的优先级高
2.1 同表子查询
举例: 查询比 路飞 工资高的员工信息
-- 先查出路飞的工资是多少
SQL> select sal from emp where ename like '%路飞%';
SAL
---------
5450.00
-- 然后再和路飞的工资比较得出查询
SQL> select ename, sal from emp where sal>(select sal from emp where ename like '%路飞%');
ENAME SAL
-------------------------------------------------- ---------
妮可·罗宾 5500.00
特拉法尔加·D·瓦铁尔·罗 5655.00
香克斯 6000.00
本·贝克曼 5500.00
耶稣布 5500.00
马歇尔·D·帝奇 5675.00
Monkey·D·Luffy 5500.00
Trafalgar·D·Water·Law 5800.00
Marshall·D·Teach 7800.00
Portgas·D·Ace 5500.00
Gol·D·Roger 7500.00
Monkey·D·Dragon 6550.00
Monkey·D·Garp 7890.00
13 rows selected
2.2 不同表子查询
举例: 查询部门名称是 草帽海贼团 的员工信息
-- 先查询部门名称是 草帽海贼团 的部门编号
SQL> select deptno from dept where dname='草帽海贼团';
DEPTNO
------
20
-- 通过部门编号过滤得到 草帽海贼团 的员工信息
SQL> select * from emp where deptno=(select deptno from dept where dname='草帽海贼团');
2.3 在select、from、where、having后边使用子查询
- 在select后使用子查询 - 不常用
查询20号部门的员工号、员工姓名、部门编号、部门名称
-- 员工信息: emp表, 可以得到 员工号、员工姓名、部门编号, 部门名称在dept表
select empno, ename, deptno, (select dname from dept where deptno = 20)
from emp
where deptno = 20;
- 在from后使用子查询 – 更不常用
在使用select进行查询的时候, from关键字值可以 指定表名 或者 一个结果集 即查询的结果. 子
查询的结果就是一个结果集, 因此可以将子查询直接写到from的后边.
-- 举例
select ename, sal from (select ename, sal, sal*12 from emp);
- where后使用子查询 --> 常用的方式
查询比平均工资高的员工信息
-- 首先查询出平均工资
SQL> select avg(sal) from emp;
AVG(SAL)
----------
3932.03733
-- 然后用在emp表中判断工资是否大于平均工资
SQL> select ename, sal from emp where sal>(select avg(sal) from emp);
ENAME SAL
-------------------------------------------------- ---------
娜美 4560.00
蒙奇·D·路飞 5450.00
妮可·罗宾 5500.00
- 在having后使用子查询
分组统计需要使用关键字: group by , 在这个关键字后边进行数据过滤需要使用关键字 having
查询部门的平均薪资, 并且该部门的平均薪资高于30号部门的平均薪资
-- 首先求出30号部门的平均薪资
SQL> select avg(sal) from emp where deptno=30;
AVG(SAL)
----------
3322.14285
-- 再分组统计每个部门的平均薪资与30号部门的平均薪资比较
SQL> select deptno, avg(sal) from emp group by deptno
having avg(sal)>(select avg(sal) from emp where deptno=30);
DEPTNO AVG(SAL)
------ ----------
40 4640
50 3996.5
10 5000
60 6248.75
-- 如果再增加需求:在结果集中, 显示部门名称和部门ID
-- 需要使用多表查询,因为部门名称在dept表中
SQL> select d.deptno, d.dname, avg(e.sal)
from emp e, dept d
where d.deptno = e.deptno
group by d.deptno, d.dname
having avg(e.sal) > (select avg(sal) from emp where deptno = 30);
DEPTNO DNAME AVG(E.SAL)
------ ------------------------------ ----------
10 周刊少年Jump 5000
40 红发海贼团 4640
60 D之一族 6248.75
50 黑胡子海贼团 3996.5
查询部门的最低月薪并且该部门最低月薪高于50号部门的最低月薪
-- 首先查询50号部门的最低月薪,再用于月薪的比较判断
SQL> select d.deptno, d.dname, min(e.sal)
from emp e, dept d
where d.deptno = e.deptno
group by d.deptno, d.dname
having min(sal) > (select min(sal) from emp where deptno = 50);
DEPTNO DNAME MIN(E.SAL)
------ ------------------------------ ----------
10 周刊少年Jump 5000
40 红发海贼团 2600
60 D之一族 3450
2.4 单行/多行子查询
- 单行子查询
单行子查询就是 该条子查询执行结束时,只返回一条记录(一行数据)。
在当行子查询中只能使用单行操作符: 使用单行操作符: = 、 > 、 >= 、 < 、 <= 、 <>
上面的例子全是单行子查询
举例: 查询工资比 路飞 工资高的员工的信息
-- 先查出路飞的工资是多少
SQL> select sal from emp where ename like '%路飞%';
SAL
---------
5450.00
-- 然后再和路飞的工资比较得出查询
SQL> select ename, sal from emp where sal>(select sal from emp where ename like '%路飞%');
- 多行子查询
多行子查询就是 该条子查询执行结束时,只返回多条记录(多行数据)。
多行操作符有:
- IN: 等于列表中的 任意 一个
- ANY: 和子查询返回的 某一个 值比较
- ALL: 和子查询返回的 所有 值比较
与每个比较运算符一起使用时的含义:
条件 | 表示含义 |
---|---|
c = ANY (…) |
c 列中的值必须与集合中的一个或多个值匹配,以评估为true 。 |
c != ANY (…) |
c 列中的值不能与集合中的一个或多个值匹配以评估为true 。 |
c > ANY (…) |
c 列中的值必须大于要评估为true 的集合中的最小值。 |
c < ANY (…) |
c 列中的值必须小于要评估为true 的集合中的最大值。 |
c>= ANY (…) |
c 列中的值必须大于或等于要评估为true 的集合中的最小值。 |
c <= ANY (…) |
c 列中的值必须小于或等于要评估为true 的集合中的最大值。 |
下表说明了SQL ALL
运算符的含义:
条件 | 描述 |
---|---|
c > ALL(…) |
c 列中的值必须大于要评估为true 的集合中的最大值。 |
c >= ALL(…) |
c 列中的值必须大于或等于要评估为true 的集合中的最大值。 |
c < ALL(…) |
c 列中的值必须小于要评估为true 的集合中的最小值。 |
c <= ALL(…) |
c 列中的值必须小于或等于要评估为true 的集合中的最小值。 |
c <> ALL(…) |
c 列中的值不得等于要评估为true 的集合中的任何值。 |
c = ALL(…) |
c 列中的值必须等于要评估为true 的集合中的任何值。 |
- 查询部门名称为 红心海贼团 和 红发海贼团 的员工信息
-- 先查询出部门名称为 红心海贼团 和 红发海贼团 的部门编号,是一个集合
SQL> select deptno from dept where dname in ('红心海贼团', '红发海贼团');
DEPTNO
------
30
40
-- 再根据这个部门编号集合查询对应的员工信息
SQL> select * from emp where deptno
in (select deptno from dept where dname in ('红心海贼团', '红发海贼团'));
- 查询所有月薪比30号部门薪资最低者的工资高的员工信息
------------------ 单行子查询处理思路 ------------------
-- 查询出30号部门工资最低者的工资
SQL> select min(sal) from emp where deptno=30;
MIN(SAL)
----------
2050
-- 再通过这个最低工资来进行过滤
SQL> select * from emp where sal>(select min(sal) from emp where deptno=30);
------------------ 单行子查询处理思路 ------------------
-- 查出30号部门的所有人的工资,组成一个集合
select sal from emp where deptno=30;
-- 通过这个集合来进行过滤,可以使用 any 关键字
SQL> select * from emp where sal>any(select sal from emp where deptno=30);
注意:>any() 表示大于any中的最小值即为true
- 查询比30号部门所有员工工资都高的员工信息
------------------ 单行子查询处理思路 ------------------
-- 查询出30号部门工资最高者的工资
SQL> select max(sal) from emp where deptno=30;
-- 再通过这个最低工资来进行过滤
SQL> select * from emp where sal>(select max(sal) from emp where deptno=30);
------------------ 单行子查询处理思路 ------------------
-- 查出30号部门的所有人的工资,组成一个集合
select sal from emp where deptno=30;
-- 通过这个集合来进行过滤,可以使用 any 关键字
SQL> select * from emp where sal>all(select sal from emp where deptno=30);
注意:>all() 表示大于any中的最大值即为true
2.5 子查询中的NULL
判断一个值等于、不等于空,不能使用=和!=号,而应该使用is 和 not。
如果集合中有NULL值, 不能使用not in。例如:not in (10, 20, NULL),但是可以使用 in
查询不是管理者的员工信息。
-- 查询的表是员工信息表-> emp
-- 如何确定员工是是不是管理者: 在数据库表的 mgr 字段的值对应的是员工的编号, 只要员工编号出现在这一列, 这个员工就是一个管理者
-- 查询是管理者的员工的信息
-- 这个查询对应的结果集中有空字段null,注意使用distinct关键字,因为不同员工有相同的管理者
SQL> select distinct mgr from emp;
MGR
-----
7839
7698
7902
7566
6100
6 rows selected
-- 上面的结果显示有6条查询,但只有5条显示,因为结果集中有null字段。
-- 所以注意要将mgr是空的条目过滤掉,使用is not null
SQL> select * from emp where empno not in(select distinct mgr from emp where mgr is not null);
3. 集合运算
3.1 交集、并集、差集
关键字: 并集:
union
, 全并集:union all
, 交集:intersect
, 差集:minus
比如说有集合 A ( 1 , 2 , 3 ) , B ( 2 , 3 , 4 ):
A∪B(取并集) = ( 1, 2, 3, 4) ,如果是全并集就是 (1, 2, 3, 2, 3, 4)
A∩B (取交集) = ( 2, 3 )
A – B(取差集) = ( 1 ) ,B – A = (4)
-- 并集
select * from emp where deptno=10
union
select * from emp where deptno=20;
-- 全并集
select * from emp where deptno=10
union all
select * from emp where deptno in(10,20);
-- 交集
select * from emp where deptno=10
intersect
select * from emp where deptno in(10,20);
-- 差集, 剩下30号部门信息
select * from emp where deptno in(10, 30)
minus
select * from emp where deptno in(10,20);
-- 交换位置, 剩下20号部门信息
select * from emp where deptno in(10, 20)
minus
select * from emp where deptno in(10,30);
3.2 集合使用的注意事项
-
参与运算的各个集合必须列数相同,且类型一致。
-- 错误的例子 -- 两个集合列数不一致, select ename, deptno from emp where deptno=10 union select * from emp where deptno=20; -- 查询的数据类型不一致 select ename, deptno from emp where deptno=10 union select deptno, ename from emp where deptno=20;
-
采用第一个集合的表头作为最终使用的表头。
select ename "员工信息", deptno "部门ID" from emp where deptno=10 union select ename "Name", deptno "ID" from emp where deptno=20;
-
可以使用括号()先执行后面的语句。
select ename "员工信息", deptno "部门ID" from emp where deptno=10 union
(select ename “Name”, deptno “ID” from emp where deptno=20);
# 4. 数据处理
## 4.1 插入数据
```sql
-- 语法格式:
insert into 表名[列名1,列名2,...] values(列值1,列值2,...);
SQL> desc bonus;
Name Type Nullable Default Comments
----- ------------ -------- ------- --------
ENAME VARCHAR2(10) Y
JOB VARCHAR2(9) Y
SAL NUMBER Y
COMM NUMBER Y
上述是一张空表,可以用来测试数据处理。
- 插入全部列
-- 给所有的列指定出数据值,这时表名后面的列名可以不写
SQL> insert into bonus values('lily','后台',10000,10000);
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
lily 后台 10000 10000
- 插入部分列/隐式插入null
-- 在插入数据的时候可指定部分列的值, 没有指定值的字段就是空字段
-- 如果指定部分列的值, 需要将列名一并写出,写在表名后面
SQL> insert into bonus(ename, sal, comm) values('tom', 20000, 10000);
1 row inserted
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
lily 后台 10000 10000
tom 20000 10000
- 显示插入null
-- 可以显示的指定某一个字段值为空
SQL> insert into bonus values('tom', null, 20000, 10000);
1 row inserted
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
lily 后台 10000 10000
tom 20000 10000
tom 20000 10000
4.2 更新数据
-- 语法结构:
update 表名 set 列名1=列值[,列名2=列值,...] where 列名=列值(条件);
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
lily 后台 10000 10000
tom 20000 10000
tom 20000 10000
SQL> update bonus set sal=25000 where ename='tom';
2 rows updated
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
lily 后台 10000 10000
tom 25000 10000
tom 25000 10000
4.3 删除数据
-- 语法格式:
delete from 表名; -- 表示删除表中的全部数据
delete from 表名 where 列名=列值(条件); -- 表示按条件筛选删除
-- 举个栗子
SQL> delete from bonus where ename='lily';
1 row deleted
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
tom 25000 10000
tom 25000 10000
SQL> delete from bonus;
2 rows deleted
SQL> select * from bonus;
ENAME JOB SAL COMM
---------- --------- ---------- ----------
4.4 事务
4.4.1 什么是数据库事务
数据库事务是构成单一逻辑工作单元的操作集合 。
多个操作的集合, 这些操作中必须要涉及到数据库数据的写操作
如果都是读操作, 根本不需要事务
比如: 转账是生活中常见的操作,比如从A账户转账100元到B账号。站在用户角度而言,这是一个逻辑上的单一操作,然而在数据库系统中,至少会分成两个步骤来完成:
将A账户的金额减少100元
将B账户的金额增加100元。
在这个过程中可能会出现以下问题:
- 转账操作的第一步执行成功, A账户上的钱减少了100元, 但是第二步执行失败或者未执行便发生系统崩溃,导致B账户并没有相应增加100元。
- 转账操作刚完成就发生系统崩溃,系统重启恢复时丢失了崩溃前的转账记录。
- 同时又另一个用户转账给B账户,由于同时对B账户进行操作,导致B账户金额出现异常。
- 这个交易的过程不能出现任何异常
- 如果出现了异常, 需要进行状态的回滚, 回滚到交易开始的时候 == > 复原
- 如何有事务就可以还原状态, 如果没有事务就无法还原
- 事务的作用:
- 在交易开始的时候开启一事务, 记录当前的状态
- 交易过程中判断每一步是否成功了, 成功: 继续, 失败: 不继续交易, 状态回滚到开始的时候
为了便于解决这些问题,需要引入数据库事务的概念。
关于事务有以下几点特性:
数据库事务可以包含一个或多个数据库操作, 但这些操作构成一个逻辑上的整体,构成逻辑整体的这些数据库操作, 要么全部执行成功, 要么全部不执行
。 – 原子性构成事务的所有操作, 要么全都对数据库产生影响, 要么全都不产生影响, 即不管事务是否执行成功, 数据库总能保持一致性状态
。 – 一致性事务的执行不受其他事务的干扰,当数据库被多个客户端并发访问时,会隔离它们的操作,防止出现:脏读、幻读、不可重复读
。 – 隔离性
- 脏读是指一个事务读取了另一个事务未提交的数据
- 不可重复读是指一个事务对同一数据的读取结果前后不一致。
- 幻读是指事务读取某个范围的数据时,因为其他事务的操作导致前后两次读取的结果不一致。
- 幻读和不可重复读的区别在于,不可重复读是针对确定的某一行数据而言, 而幻读是针对不确定的多行数据。
对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障
。–持久性
4.4.2 oracle中的事务
-
设置保存点
-- 在写数据库之前, 需要设置保存点 ===> 开启了一个事务 -- 保存点的名字不允许重名 sql> savepoint 保存点的名字;
-
回滚到保存点
-- 事务对应的操作集合有一步失败了, 需要进行数据的回滚 -- 回滚就是内存数据的覆盖, 用旧的数据覆盖新的数据
sql> rollback to savepoint 保存点的名字;
- 提交事务
```sql
-- 提交之后保存点就不存在了, 提交之后不能回滚
-- 提交就是将内存数据写入到磁盘的数据库文件中
sql> commit;
-
举例
-- 一个完整的操作(一个事务), 这个操作需要若干步来完成 -- 设置一个保存点 a -- 状态: 空表 SQL> savepoint a; Savepoint created -- 插入数据 SQL> insert into bonus values('tom', '董事长', 10000, 2000); 1 row inserted SQL> insert into bonus values('jack', '销售', 1000, 2000); 1 row inserted -- 添加保存点 b -- 状态: 数据库表中 有两条记录 SQL> savepoint b; Savepoint created SQL> insert into bonus values('lucy', '秘书', 10000, 20000); 1 row inserted SQL> insert into bonus values('lily', '小秘书', 9000, 20000); 1 row inserted -- 添加保存点c -- 数据库表中有4条数据 SQL> savepoint c; Savepoint created SQL> delete from bonus where ename = 'lily'; 1 row deleted SQL> select * from bonus; ENAME JOB SAL COMM ---------- --------- ---------- ---------- tom 董事长 10000 2000 jack 销售 1000 2000 lucy 秘书 10000 20000 -- 回滚到保存点c -- 重新回到有4条记录的表状态 SQL> rollback to savepoint c; Rollback complete SQL> select * from bonus; ENAME JOB SAL COMM ---------- --------- ---------- ---------- tom 董事长 10000 2000 jack 销售 1000 2000 lucy 秘书 10000 20000 lily 小秘书 9000 20000 -- 当确定所有的数据库操作都没有问题, 提交事务 SQL> commit; Commit complete
下一篇: oralce执行计划