JavaWeb之SQL语句
一、数据库
1.数据存储
存储方式 | 优点 | 缺点 |
---|---|---|
数组、集合 | 速度快 | 不能永久保存,数据是临时数据 |
数据库 | 数据可以永久保存、查询速度快、方便管理数据 | 占用资源,需要购买 |
(1)集合、数组:容器,使用完毕就不存在了集合对象/数组被回收。
(2)IO流:字节流/字符流,将数据存储到配置文件/xxx.txt文件中 ,效率低。
(3)数据库软件:
关系型数据库
SQLServer,Oracle,db2,Mysql(开源,小型化)
非关型数据库
典型代表:mangodb/redis(key-value形式)—(缓存一些数据)
2.MySql数据库
(1)验证是否安装完毕(登录成功,说明mysql的环境变量也配置了)
(2)四个:mysql默认带的四个库
mysql> show databases;
information_schema:相关配置信息库
mysql:存储相关表:user 用户表(管理员)
performance_schema:mysql性能相关的
test:测试的库
3.数据库的备份和还原
(1)备份
1)命令行的方式:进入dos
备份的语法格式:
mysqldump -u用户名 -p密码 数据库的名称 > 保存的路径
举例:备份day31 数据库中的数据到 d:\day31.sql文件中。
mysqldump -uroot -proot day31 > d:/day31.sql
2)使用图形界面化工具的方式来进行数据库的备份
进入到sqlyog工具中,在数据库的上面右键,选择备份。
(2)还原数据库
1)进入dos之后:登录msyql数据库,删除当前day31这个数据库。
还原格式:source 之前备份的sql文件路径,回车
举例:source d:/day31.sql;
2)图形界面化的方式
在sqlyog中删除当前day31数据库,然后右键选择以sql的转存文 件来导入。
4.表与表之间的关系
(1)三种关系
一对一:相对使用比较少,员工表–简历表,公民表–护照表。
一对多:最常用的关系,部门和员工。
多对多:学生选课表和学生表,一门课程可以有多个学生选择,一个学 生选择多门课程。
(2)一对一 (1:1)
1)一对一:在实际的开发中应用不多.因为一对一可以创建成一张表。
2)两种建表原则:
外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外 键唯一 UNIQUE 。
外键是主键:主表的主键和从表的主键,形成主外键关系。
(3)一对多(1:n)
1)例如:班级和学生,部门和员工,客户和订单,分类和商品
2)一对多建表原则: 在从表(多方)创建一个字段,字段作为外键指向主 表(一方)的主键。
(4)多对多(m:n)
1)例如:老师和学生,学生和课程,用户和角色。
2)多对多关系建表原则: 需要创建第三张表,中间表中至少两个字段, 这两个字段分别作为外键指向各自一方的主键。
(5)总结
一对多:主外键的关系。
多对多:中间表,两个一对多 。
一对一:1) 特殊一对多,从表中的外键设置为唯一 。
2) 从表中的主键又是外键。
5.数据规范化
(1)范式:好的数据库设计对数据的存储性能和后期的程序开发,都会产生重要的影响。
建立科学的,规范的数据库就需要满足一些规则来优化数据的设计和存储,这些规则就称为范式。
(2)三大范式:目前关系型数据库有六种范式
第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、 第四范式(4NF)和第五范式(5NF,又称完美范式)。
满足最低要求的范式是第一范式(1NF)。
在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。
一般说来,数据库只需满足第三范式(3NF)就行了。
(3)第一范式:1NF
1)概念:数据表的每一列都是不可再分割的原子数据项,不能是集合、 数组等非原子数据项。
表中的某个列有多个值时,必须拆分为不同的列。
简而言之,第一范式每一列不可再拆分,称为原子性。
2)示例:班级表
(4)第二范式:2NF
1)概念: 在满足第一范式的前提下,表中的每一个字段都完全依赖于主 键。
所谓完全依赖是指不能存在仅依赖主键一部分的列。
简而言之,第二范式就是在第一范式的基础上所有列完全依赖于主键列。
当存在一个复合主键包含多个主键列的时候,才会发生不符合第二范式的情况。
比如有一个主键有两个列,不能存在这样的属性,它只依赖于其中一个列,这就是不符合第二范式。
2)特点:
一张表只描述一件事情。
表中的每一列都完全依赖于主键。
3)示例:
借书证表(学生证号、学生证名称、学生证办理时间、借书证号、借 书证名称、借书证办理时间)
分成两张表
学生证表(学生证号、学生证名称、学生证办理时间)
借书证表(借书证号、借书证名称、借书证办理时间)
(5)第三范式:3NF:
1)概念:在满足第二范式的前提下,表中的每一列都直接依赖于主键, 而不是通过其它的列来间接依赖于主键。
第三范式就是所有列不依赖于其它非主键列,也就是在满足2NF的基础上,任何非主列不得传递依赖于主键。
2)传递依赖:指的是如果存在"A → B → C"的决定关系,则 C 传递依赖于A。
因此,满足第三范式的数据库表应该不存在如下依赖关系:主 键列 → 非主键列 x → 非主键列 y。
3)示例:
学生信息表(学号、姓名、年龄、所在学院、学院地点)
存在传递的决定关系:学号—>所在学院—>学院地点。
拆分成两张表
学生信息表(学号、姓名、年龄、所在学院的编号(外键))
学院信息表(学院编号、所在学院、学院地点)
(6)三大范式总结:
1NF:原子性,表中每列不可再拆分。
2NF:不产生局部依赖,一张表只描述一件事情。
3NF:不产生传递依赖,表中每一列都直接依赖于主键,而不是通过其它 列间接依赖于主键。
二、SQL语句之DDL、DML语句
1.SQL
(1)SQL:Structured Query Language 结构化查询语言。
(2)SQL作用
1) 是一种所有关系型数据库的查询规范,不同的数据库都支持。
2) 通用的数据库操作语言,可以用在不同的数据库中。
3) 不同的数据库 SQL 语句有一些区别
(3)SQL语句分类
1)Data Definition Language (DDL 数据定义语言),如:建库,建表
2)Data Manipulation Language(DML 数据操纵语言),如:对表中的记 录操作(增删改查)。
3)Data Query Language(DQL 数据查询语言),如:对表中数据的查询操 作 。
4)Data Control Language(DCL 数据控制语言),如:对用户权限的设置
(4)MySQL的语法
1)每条语句以”;”结尾,如果在 SQLyog 中不是必须加的。
2)SQL中不区分大小写,关键字中认为大写和小写是一样的。
3)3种注释:
单行注释:–空格
多行注释:/* */
# :这是 mysql 特有的注释方式
2.DDL操作数据库
(1)创建数据库
方式1:create database 数据库名;
方式2: create database if not exists 数据库名;
如果不存在这个库,创建一个新的。
方式3:创建数据库的时候直接指定库的字符集
create database if not exists 数据库名 default(不写) characterset 字符集 ;
(2)查看数据库
1)查看所有数据库
show databases;
2)查看数据库的定义信息 (数据库名,以及数据库的默认的编码格式)
show create database 数据库名;
(3)修改数据库的编码格式为gbk
alter databse 数据库名 default(省略不写) character set 字符集;
(4)删除数据库
方式1:drop database 数据库名;
方式2:drop database if exists 数据库名;
如果存在,删除该库
(5)使用数据库
use 数据库名;
select database();
查看正在使用的数据库
3.DDL语句操作表
(1)常见字段类型:
1)varchar(m):m多少个字符,mysql字符串类型。
2)int:默认int(11),11位(记录实际字符),int(num)参数指定长度, mysql整数类型。
3)double(5,2):mysql的小数类型,表示小数5位,小数点后保留2位。
4)date:mysql的日期时间,仅仅是日期(年月日),不包含具体时间。
5)datetime:mysql的日期时间,是日期+具体时间(年月日 时分秒)
6)timestamp(时间戳):具体哪个时间操作的表。
例如:2020//11/15 16:16这个时间修改了表的字段。
(2)创建表
1)格式:
create table 表名(
字段名称1 字段类型1,
字段名称2 字段类型2,
字段名称3 字段类型3,
…
字段名称n 字段端类型n
);
2)在创建表之前,先使用这个库
use 数据库名
mysql> use mydb_01;
Database changed
3)在mydb_01创建一个学生表
学生表: 字段 数据类型
姓名 varchar(3)
年龄 int
性别 varchar(2)
分数 double
出生日期 date
4)快速创建一个表结构相同的表。
(3)查看表
1)查询该库中的所有表
show tables;
2)查询表的结构
desc 表名;
3)查看创建表的sql语句
(4)修改表
1)给表中新增一列 (加入一个新的字段)
alter table 表名add 字段名 字段数据类型;
2)修改表中字段的数据类型
alter table 表名 modify 字段名 字段数据类型;
3)修改表表中字段的名称 change
alter table 表名 change 旧字段名 新字段名 新字段数据类型;
4)删除列 DROP
alter table 表名 drop 列名;
5)修改表的名称
alter table 表名 rename to 新表名;
6)修改字符集 character set
alter table 表名 character set 字符集;
(5)删除表
1)drop table 表名;
2)drop table if exists 表名;
如果这个表存在,就删除
4.DML语句:操作数据语句
(1)插入数据
1)方式1::给表中的每一个字段赋值
insert into 表名 values(值1,值2,值3,…)
2)给部分字段赋值
insert into 表名(id,name,age,gender) values(值1,…) ;
3)注意事项:
①插入数据的时候,插入字段顺序必须要和表的字段对应上;
②如果是给全部字段插入数据,中间逗号隔开,依次插入多条语句!
③没有赋值的字段都是NULL(空值)
④数据的大小应在列的规定范围内。
⑤插入的数据应与字段的数据类型相同。
⑥字符和日期型数据应包含在单引号中。
(2)蠕虫复制
将一张已经存在的表中的数据复制到另一张表中。
1)将表名 2 中的所有的列复制到表名 1 中
INSERT INTO 表名1 SELECT * FROM 表 名 2;
2)只复制部分列
INSERT INTO 表名1( 列 1,列 2) SELECT 列 1,列 2 FROM 表名2;
(2)删除表的记录
1)带条件删除
delete from 表名 where 字段名=值;
2)删除全表数据:
truncate table 表名 和 delete from 表名的区别
①delete from 表名:删除全表数据
TRUNCATE table 表名 :删除表以及表中的数据,再创建一张一模一样的表。
②是否对自增长的主键影响
delete from 表名:不会影响自增长的主键,只删除全表的数据,不会清除自增长主键。
TRUNCATE TABLE 表名:直接删除了表,并且同时创建一张一模一样的表,自增长主键会清除掉。
(3)修改表中数据
1)带条件修改单个字段数据
update 表名 set 字段名 = 赋值 where 字段 = 值;
注意:update语句都需要带上where条件,否则就是"批量修改"
2)修改多个字段的数据
将id=4的这个人 name=‘高阳’ 并将年龄改成30
三、DQL语句:数据查询语句
1.基本的查询语句
(1)查询全表数据
select 全部字段(*) from 表名;
(2)查询指定的字段
select 字段名,字段名… from 表名;
需求:查询id,name,age字段
(3)去重
将字段去重查询
select distinct 字段名称 from表名
(4)查询结果参与运算
1)某列数据和固定值运算
SELECT 列名 1 + 固定值 FROM 表名;
2)某列数据和其他列数据参与运算
SELECT 列名 1 + 列名 2 FROM 表名;
需求:查询name,总分成绩
3)注意事项:对两个字段进行求和,两个字段类型必须一致:int类型 (math+english)。
(4)起别名查询
1)给字段起别名
select 字段名称 as(可省略不写) ‘名称’ from 表名
2)给表起别名
select 表别名.字段名称 from 表名 别名;
2.基本条件查询:where语句
(1)基本的条件关系符号
比较:使用表达式符号<,>,<=,<=,<>(不等于,mysql的语法,!=也可以使 用)。
并列关系:and、&&、between and。
或的关系:or、||
集合:in(18,25,19)
是否是空: is null :xxx是null值
is not null:不是null
非:!、not
(2)等于(=)
select * from 表名 where 字段名=字段值;
举例:查询年龄是30的人
(3)查询在某个字段一定范围的数据
1)大于等于某个值的范围(>=)
举例:查询年龄大于20的人
2)在某两个值之间的范围(>= + && + <=)
需求:查询年龄在20岁和30岁之间的人(包含两端)
3)and用法(>= + and + <=)
4)between…and…(等价于>= + and + <= )
(4)是否为空
1)is null(为空)
需求:查询英语成绩为null的学生信息。
2)is not null(不为空)
查询英语成绩不为空的学生信息。
(5)不等于
1)java语法:!=
需求:查询年龄不等于20岁的学生信息。
2)推荐mysql语法:<> 不等于
(6)或
1)||连接
需求:查询年龄是25岁或者18岁或者20岁的人。
2)or连接
3)in(集合数据):可以填多个数据
3.模糊条件查询
(1)关键字:like
两个符号:
%:表示多个任意字符
_:代表一个字符
(2)格式:select 字段名称 from 表名 where 某个字段 like ‘模糊符号’;
(3)查询某个字段的第一个字符是指定字符的数据
举例:查询姓名第一个字符是’小’的学生信息
(4)查询某个字段的第二个字符是指定字符的数据
举例:查询学生姓名第二个字符是’化’的学生信息
(5)查询某个字段是指定字符个数的数据
举例:查询学生姓名是三个字符的人
(6)查询某个字段中有指定字符的数据
举例:查询学生姓名中包含’小’字的人
(7)查询某个字段中没有指定字符的数据
举例:查询学生姓名中不包含’小’字的人
(8)如果dos中出现中文乱码,查询所有包含’character’的变量
SHOW VARIABLES LIKE ‘%character%’ ;
4.查询排序
(1)关键字:order by
asc :升序排序
desc:降序排序
(2)格式:
select 字段名称列表 from 表名 order by 排序的字段 排序规则;
(3)如果执行排序的时候,某个字段后面没有跟排序规则:默认升序排序(整数类型)。
(4)升序排序
举例:按照身高升序排序
(5)降序排序
举例:按照体重降序排序
(6)针对多个字段同时排序
需求:查询全表数据,体重升序,身高降序。
(7)多个字段同时排序:
优先按照第一个字段的排序规则排序,
第一个字段排序值如果相同,
这个时候再按照第二个字段排序规则排序。
5.聚合函数
(1)常用函数:
count函数:统计记录数
max函数:最大值
min函数:最小值
avg函数:平均数
sum函数:求和
(2)count(非业务字段)
count的使用:一般都是用表的非业务字段,如id。
需求:统计当前表中总记录数有多少条
(3)max(数值型字段)
需求:查询数学成绩的的最高分的学生信息
(4)avg(数字型字段)
举例:查询英语平均分
(5)sum(任意个数数值型字段)
举例:查询数学与英语的总分
(6)min(数字型字段)
需求:查询数学成绩的的最低分的学生信息。
(7)函数:ifnull(字段名,默认值)
ifnull(字段名,默认值):如果当前字段名称是null值,使用默认值给它 赋值。
例如:当前何瑾的英语成绩为null
在获取英语成绩的时候提供一个函数ifnull(english,0)。
6.分组查询
(1)分组:分组查询是指使用group by语句对查询信息进行分组,相同数据作为一组,进行数据统计。
(2)格式:group by 分组字段
(3)group by分组查询,如果带有条件进行分组查询,要先去判断条件,再进行分组,即先where,后group by。
(4)查询的字段:要有分组字段,还有聚合函数。
(5)按照某个字段分组
需求:查询数学平均分并且按照性别进行分组
(6)按照指定条件,进行某个字段分组
需求:查询数学的平均分,并且按照性别分组。
条件:数学成绩小于70分的学生不参与分组。
7.筛选
(1)关键字:having
(2)格式:having 筛选的字段(字段是查询结果中存在的字段)
(3)需求:查询数学的平均分 并且按照性别分组。
条件:数学成绩小于70分的学生不参与分组。
帅选条件:总人数大于2等于个人的
(4)变形
SELECT sex '性别',AVG(math) '数学平局分',COUNT(id) ‘人数’
FROM student3
WHERE math > 70
GROUP BY sex
HAVING '人数'>= 2;
(5)having和group by的区别
1)group by是在where条件后面用,不能使用聚合函数的,但是查询的 时候可以查询聚合函数。
2)having是在group by 后面使用,后面可以跟聚合函数。
3)having:是需要放在group by 后面,不能放置在group by 之前。
(6) having 与 where 的区别
where 子句 :
1)对查询结果进行分组前,将不符合 where 条件的行去掉,在分组之前过滤数据,即先过滤再分组。
2)where 后面不可以使用聚合函数 。
having子句:
1)having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,即先分组再过滤。
2) having后面可以使用聚合函数。
8.分页查询
(1)关键字:limit是限制的意思,所以 LIMIT 的作用就是限制查询记录的条数。
(2)语法格式:limit 起始行数,每页显示的条数。
limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
(3)举例:起始行数:从0开始,每页展示3条数。
查询第一页的数据
查询第二页的数据:每页2条
查询第一页:从0开始,每页4条
四、数据库约束
1.数据库约束
(1)约束:通过一些特定的关键字 保证数据的安全性,正确性和有效性。
(2)常见约束
默认约束:字段名称 类型 default ‘值’
非空约束:not null
唯一约束:unique
主键约束:primary key
自增长约束:auto_increment
外键约束:foreign key
2.默认约束:default
(1)默认约束:是当某个字段没有赋值的时候起作用,如果赋值了,那么按照实际值赋值即可。
(2)为某个字段添加默认约束
alter table 表名 modify 字段名 字段数据类型 default ‘默认值’;
(3)创建表时添加默认约束
字段名称 类型 default ‘默认值’;
(4)举例:向teacher表中插入两条数据,做对比
(5)数据不安全,默认约束可以插入null。
为了防止插入的字段不是null,可以给表加入非空约束。
(6)删除默认约束(修改表字段类型)
alter table 表名modify 有默认约束的字段 字段类型;
3.非空约束:not null
(1)非空约束:加入非空约束的字段其值不能是null。
(2)创建表时给某个字段添加非空约束。
字段 字段数据类型 not null;
(3)给表中某个字段添加非空约束。
alter table 表名moify 字段名 字段数据类型 not null;
(4)举例:向表中添加一条name为空的数据;
错误:列“name”不能为空。
非空约束不能添加null,但可以添加’ ’。
(5)删除非空约束(修改表字段类型)
alter table 表名 modify 有非空约束的字段 字段数据类型;
4.唯一约束:unique
(1)唯一约束:字段值不能重复。
(2)创建表时为某字段添加唯一约束
字段名 字段类型 unique
(3)为表中某个字段添加唯一约束
alter table 表名 modify 字段名 字段类型 unique;
(4)举例:向表中添加两条phone值相同的数据
错误:phone项重复
(5)删除唯一约束
alter table 表名drop index 有唯一约束的字段;
5.主键约束:primary key
(1)主键约束:非空且唯一,主键都应用在非业务字段上。
(2)创建表时添加主键约束
非业务字段名 字段类型 primary key
(3)添加主键
给表中的已有id字段添加主键
alter table 表名 add primary key(id);
添加id字段并添加主键
alter table 表名 add id int primary key;
修改id的数据类型,并添加主键
alter table 表名 modify id int primary key;
(4)一个表中的字段有:非业务字段(id)和业务字段(name,age等)。
业务字段可能随着需求的变化不断变化,所以不会在业务字段上加入 primary key,都是给每一张表的id字段设置主键和自增长。
(5)举例:添加两条id相同的数据
错误:id值11重复
添加一条id为null的数据
添加一条id为0的数据
添加一条没有id值的数据
添加两条id值为0的数据
结论:添加主键约束的非业务字段,其值不能为null,可以为0,如果不写,默认添加0值,0值只能添加一次。
(6)删除主键约束
alter table 表名 drop primary key;
6.自增长约束:auto_increment
(1)自增长约束:id值自增从起始索引0一直++。
(2)创建表时为id添加自增长约束
id int auto_increment
(3)为表中的id字段添加自增长约束
alter table 表名 modify id int primary key auto_increment;
如果表中存在id为0的数据,添加自增长会与主键的唯一性冲突。
(4)修改自增长的起始值
在创建表时修改
CREATE TABLE 表名( 列 名 int primary key AUTO_INCREMENT )
AUTO_INCREMENT=起始值;
表创建好之后修改
ALTER TABLE 表名 AUTO_INCREMENT=起始值;
(4)添加一条没有id值的数据:id值为上一条数据的id值加1.
(5)删除自增长约束(修改id的类型)
alter table 表名 modify id int;
7.外键约束
(1)外键约束:让多个表之间产生一种关系,来保证数据的安全性和有效性。
主表:没有外键的表。
从表:表中有外键声明。
(2)引入:
部门名称:字段值大量冗余(重复名称)
1)解决字段的冗余问题
方案:单独的在创建一张表:部门表 dept表,存储者三个部门:研发 部,测试部, 销售部。
将原来的部门名称换为部门表中对应部门的id。
2)问题:往员工表中插入一条不存在的部门数据,依然可以插入成功(存 在非法数据)。
解决:为了防止表中有非法数据,加入一种潜在关系,外键约束
给某个字段设置外键约束
constraint(声明) 外键名称
foreign key 员工表的dept_id
reference(关联) 部门表(主键id)
(3)创建表时为某个字段添加外键约束
constraint 外键名称 foreign key (表中要添加外键的字段)
reference 主表(主表的主键)
表中要添加外键的字段的命名:主表名_id。
外键名称:主表名_从表名_fk;
(4)如果要给从表中添加主表没有的数据,需要先在主表添加。
不能直接修改/删除当前字段,除非当前这个表字段和主表的id字段没 有关联关系,才能修改。
(5)给已有表中的某个字段添加外键
ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称]
FOREIGN KEY (外键字段名) REFERENCES 主表(主键字段名);
[CONSTRAINT] [外键约束名称]:声明外键约束名称,可以不写,为默认 名字。
(6)删除外键
ALTER TABLE 从表 drop foreign key 外键名称;
(7)什么是级联操作:
在修改和删除主表的主键时,同时更新或删除副表的外键值,称为级联 操作。
(8)级联操作语法
ON UPDATE CASCADE:级联更新。
ON DELETE CASCADE: 级联删除。
注意:只能是在添加外键的时候添加级联关系。
更新主表中的主键,从表中的外键列也自动同步更新。
(9)添加外键约束,同时添加级联更新和删除。
constraint 外键约束名称 foreign key (外键字段名)
references 主表(主表主键) on update cascade on delete cascade;
五、多表查询
1.多表查询
(1)多表查询:通过查询两张或者两张以上的表时使用的sql语句。
(2)多表查询分类:
内连接:隐式内连接、显式内连接。
外连接:左外连接、右外连接。
(3)直接查询两张表或多张表存在问题:产生笛卡尔乘积。
A表中有n条数据,B表中有m条数据
select * from A,B;n*m=总条数
(4)解决上面笛卡尔积的方案
满足条件:
1)查询哪个:表员工表和部门表。
2)查询指定表中的哪些字段:查询所有
3)这些表的连接接条件:员工表的dept_id部门编号依赖于部门表的主键id,即员工表.dept_id=部门表.id。
2.多表查询之内连接
(1)隐式内连接:条件使用WHERE指定。
(2)格式:select 字段名列表 from 表名列表 where 连接条件;
(3)使用
1)多表查询所有字段
2)多表查询,查询指定字段
3)给表起别名
(4)显示内连接:使用 INNER JOIN … ON 语句, 可以省略 INNER
(5)格式:select 字段名列表 from 表名1 inner join 表名2 on 连接条件;
(6)使用
1)查询部分字段,给表起别名,不省略inner
2)查询所有关键字,省略inner
3.多表查询之外连接
(1)左外连接:将左表的数据全部查询,并查询交集部分(连接条件)。
(2)格式:select 字段列表
from 左表(表名1)
left outer join 右表(表名2)
on 连接条件
(3)使用
查询所有学生的信息以及所在班级
(4)右外连接查询:将右边全部显示,以及多个表的交集部分数据(连接条件)。
(5)格式:select 字段列表
from 左表(表名1)
right outer join 右表(表名2)
on 连接条件;
(6)使用
查询所有班级的学生信息。
(7)特点:
1)左外连接:用左边表的记录去匹配右边表的记录,如果符合条件的则 显示;否则,显示 NULL 。
可以理解为:在内连接的基础上保证左表的数据全部显示。
2)右外连接:用右边表的记录去匹配左边表的记录,如果符合条件的则 显示;否则,显示 NULL 。
可以理解为:在内连接的基础上保证右表的数据全部显示。
4.多表查询之子查询
(1)子查询:
1)一个查询的结果做为另一个查询的条件;
2)有查询的嵌套(select 嵌套select语句),内部的查询称为子查询;
3) 子查询要使用括号;
(2)子查询结果的三种情况:
1)子查询的结果是单行单列
2)子查询的结果是多行单列
3)子查询的结果是多行多列
(3)子查询结果是一个值
1)格式:SELECT 查询字段 FROM 表 WHERE 字段=(子查询);
select 字段列表
from 表名
where 字段名(<,<=,>=,>,=)
(select 字段列表
from 表名…)
2)举例:查询最大年龄的学生信息。
3)举例:查询大于平均年龄的学生信息
(4)子查询结果是一个字段的多个值(多行单列)
1)格式:SELECT 查询字段 FROM 表 WHERE 字段 IN (子查询);
select 字段列表
from 表名
where 字段名 in(select 字段列表
from 表名…)
2)举例:查询指定班级的学生信息
3)in(多个值)实现
(5)子查询的结果是多个字段的多个值(多行多列,即参与子查询的表的子表)
1)多行多列:将一个表的查询结果作为一个虚表来进行二次查询。
2)格式:SELECT 查询字段 FROM (子查询) 表别名 WHERE 条件;
3)注意:子查询结果只要是多列,肯定在 FROM 后面作为表(虚表,不是真 实存在的表)。
子查询结果作为表需要取别名,否则这张表没有名称则无法访问表中的字段。
4)举例:查询年龄大于20的学生信息,并查看所在班级
5)优化
六.事务
1.事务
(1)事务:将整个业务操作看成一个整体; 这些事务的执行要么同时成功,要么同时失败。
(2)事务原理
事务开启之后, 所有的操作都会临时保存到事务日志中, 事务日志只有 在得到 commit命令才会同步到数据表中,其他任何情况都会清空事务 日志(rollback,断开连接)。
(3)原理图:
(4)事务的步骤:
1)客户端连接数据库服务器,创建连接时创建此用户临时日志文件。
2)开启事务以后,所有的操作都会先写入到临时日志文件中。
3)所有的查询操作从表中查询,但会经过日志文件加工后才返回。
4)如果事务提交则将日志文件中的数据写到表中,否则清空日志文件。
2.回滚点
(1)回滚点
在某些成功的操作完成之后,后续的操作有可能成功有可能失败,
但是不管成功还是失败,前面操作都已经成功,可以在当前成功的位置设置一个回滚点。
可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点。
(2)回滚点的操作语句
设置回滚点:savepoint 回滚点名字
回到回滚点:rollback to 回滚点名字
(3)操作案例:
1)开启事务;
2)让张三账号减3次钱,每次10块;
3)设置回滚点:savepoint three_times;
4)让张三账号减4次钱,每次10块;
5)回到回滚点:rollback to three_times。
(4)总结:设置回滚点可以在事务操作失败的时候回到回滚点,而不是回到事务开启的时候。
3.事务提交方式
(1)事务的两种提交方式:
1)手动提交事务
2)自动提交事务
(2)当前提交方式的查看和修改:
查看:SELECT @@autocommit ;
修改:set @@autocommit = 0 ;
1:默认自动提交
0:非自动提交(关闭自动提交,需手动提交)
针对DML语句:增删改,数据自动提交的。
(3)手动提交事务
1)用到的语句:
start transaction ;开启事务
rollback ; 回滚事务,回滚到操作语句之前。
commit; 提交数据
2)如果开启事务:针对数据进行增删改,这些语句执行完毕之后必须 commit(手动提交)。
(5)手动提交案例
开启事务
START TRANSACTION ;
– 张三给李四转账500
UPDATE account SET balance = balance - 500 WHERE id = 1 ;
UPDATE account SET balance = balance + 500 WHERE id = 2 ;
– 回滚事务 :如果执行sql语句时出现异常,回滚到操作语句之前的状 态(两个账户都没有转钱)。
ROLLBACK;
– 提交事务:如果执行sql没有问题就提交,提交之后再修改数据表数 据。
COMMIT ;
(6)自动提交事务
MySQL 默认每一条 DML(增删改)语句都是一个单独的事务,
每条语句都会自动开启一个事务,语句执行完毕自动提交事务,
MySQL 默认开始自动提交事务。
4.事务的特性:ACID
(1)原子性(Atomicity):事务是不可分割的,要么sql同时执行成功,要么同时执行失败。
(2)一致性(Consistency):事务在执行前数据库的状态与执行后数据库的状态保持一致,即操作的数据总量不发生变化。
(3)隔离性(Isolation):事务和事务之间是独立的,比如:修改账户/ 添加/删除,每一个具体业务都是独立的事务。
(4)持久性(Durability):一旦事务执行成功,对数据库的修改是持久的。就算关机,也是保存下来的。
5.数据库的并发访问问题
(1)事务在操作时的理想状态:所有的事务之间保持隔离,互不影响。因为并发操作,多个用户同时访问同一个数据。
(2)可能引发的并发访问问题:
1)脏读:是最危险的,一个事务读取到了另一个没有提交的事务。
2)不可重复读:一个事务中两次读取的数据内容不一致,
要求的是一个事务中多次读取时数据是一致的,
这是事务update时引发的问题。
3)幻读:一个事务中两次读取的数据的数量不一致,
要求在一个事务多次读取的数据的数量是一致的,
这是insert 或 delete 时引发的问题。
(3)解决方式:逐级提升隔离级别,可以逐个解决,serializable级别可以解决所有问题。
6.事务的隔离级别
(1)mysql的隔离级别默认第三种:repeatable-read:可重复读。
(2)四个隔离级别
1)read uncommitted :可以读到未提交的事务,安全性最差,出现脏读,不可重复读,幻读问题。
2)read committed:只能读到已提交的事务,但是两次读取的结果不 一 致。
3)repeatable read: 可重复读,多次读取的结果一致。
4)serializable :串行化,隔离级别最高。
(3)隔离级别越高,事务执行越安全,性能越低。
(4)查看事务的隔离级别:
select @@tx_isolation;
(5)设置隔离级别:
set global transaction isolation level 隔离级别名称;