alin的学习之路(数据库篇:三)(多表查询,子查询,集合运算,数据处理)

3 篇文章 0 订阅
3 篇文章 0 订阅

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 Brook                                                3000.00 草帽海贼团
 
 -- 其中emp后面的e,以及dept后面的d,表示表的别名。可以用来修饰列名。
 -- 也可以不用别名直接用表名,会显得冗杂
  • 不等值连接
  1. 询员工信息:员工号, 姓名, 月薪 和 月薪级别(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
  1. 按部门统计员工人数,显示如下信息:部门号,部门名称,人数
-- 部门号和部门名称在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)。
对于外连接, 可以使用“(+) ”来表示。 关于使用(+)的一些注意事项:

  1. (+)操作符只能出现在WHERE子句中。
  2. 当使用(+)操作符执行外连接时,如果在WHERE子句中包含有多个条件,则必须在所有条件
    中都包含(+)操作符。
  3. (+)操作符只适用于列,而不能用在表达式上。
  4. (+)操作符不能与 OR 和 IN 操作符一起使用。
  5. (+)操作符只能用于实现左外连接和右外连接,而不能用于实现完全外连接。
    通过 (+) 就可以对查询的结果进行补充, 补充不满足条件的那一方
    举例: 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的集合中的任何值。
  1. 查询部门名称为 红心海贼团 和 红发海贼团 的员工信息
-- 先查询出部门名称为 红心海贼团 和 红发海贼团 的部门编号,是一个集合
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 ('红心海贼团', '红发海贼团'));
	
  1. 查询所有月薪比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
  1. 查询比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 集合使用的注意事项

  1. 参与运算的各个集合必须列数相同,且类型一致

    -- 错误的例子
    -- 两个集合列数不一致, 
    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;
    
  2. 采用第一个集合的表头作为最终使用的表头。

    select ename "员工信息", deptno "部门ID" from emp where deptno=10 
    	union
    select ename "Name", deptno "ID" from emp where deptno=20;
    
  3. 可以使用括号()先执行后面的语句。

    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账号。站在用户角度而言,这是一个逻辑上的单一操作,然而在数据库系统中,至少会分成两个步骤来完成:

  1. 将A账户的金额减少100元

  2. 将B账户的金额增加100元。

在这个过程中可能会出现以下问题:

  1. 转账操作的第一步执行成功, A账户上的钱减少了100元, 但是第二步执行失败或者未执行便发生系统崩溃,导致B账户并没有相应增加100元。
  2. 转账操作刚完成就发生系统崩溃,系统重启恢复时丢失了崩溃前的转账记录。
  3. 同时又另一个用户转账给B账户,由于同时对B账户进行操作,导致B账户金额出现异常。
  4. 这个交易的过程不能出现任何异常
    • 如果出现了异常, 需要进行状态的回滚, 回滚到交易开始的时候 == > 复原
    • 如何有事务就可以还原状态, 如果没有事务就无法还原
  5. 事务的作用:
    • 在交易开始的时候开启一事务, 记录当前的状态
    • 交易过程中判断每一步是否成功了, 成功: 继续, 失败: 不继续交易, 状态回滚到开始的时候

为了便于解决这些问题,需要引入数据库事务的概念。

关于事务有以下几点特性:

  1. 数据库事务可以包含一个或多个数据库操作, 但这些操作构成一个逻辑上的整体,构成逻辑整体的这些数据库操作, 要么全部执行成功, 要么全部不执行。 – 原子性
  2. 构成事务的所有操作, 要么全都对数据库产生影响, 要么全都不产生影响, 即不管事务是否执行成功, 数据库总能保持一致性状态。 – 一致性
  3. 事务的执行不受其他事务的干扰,当数据库被多个客户端并发访问时,会隔离它们的操作,防止出现:脏读、幻读、不可重复读 。 – 隔离性
  • 脏读是指一个事务读取了另一个事务未提交的数据
  • 不可重复读是指一个事务对同一数据的读取结果前后不一致。
  • 幻读是指事务读取某个范围的数据时,因为其他事务的操作导致前后两次读取的结果不一致。
  • 幻读和不可重复读的区别在于,不可重复读是针对确定的某一行数据而言, 而幻读是针对不确定的多行数据。
  1. 对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。–持久性

在这里插入图片描述

在这里插入图片描述

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
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值