JavaWEB-02-MySQL高级
内容
- 约束
- 多表关系
- 一对一
- 一对多
- 多对多
- 多表联查 ==多表联查==
- 事务
1. 约束
1.1 概念
限制,在数据库中是对某一列(多列)进行限制。
对表中的数据进行限定,保证正确性、有效性、完整性。
含有约束的字段,在添加记录的时候,就会自动校验添加的值是否符合约束要求。继而保证数据库中数据的正确性、有效性和完整性。
1.2 分类
大体上分为单表约束和多表约束。
约束分类:
约束类型 中文名 作用 单表约束 PRIMARY KEY 主键约束 主键是一行记录的唯一标识,要求非空唯一 PRIMARY KEY AUTO_INCREMENT 主键自增约束 主键自动增长 UNIQUE 唯一约束 要求列中所有数据值均不相同 NOT NULL 非空约束 要求列中所有数据值不能为 NULL
DEFAULT 默认约束 添加记录时,有默认约束的列如未指定值则采用默认值 CHECK 检查约束 要求列中的值满足某一条件。 MySQL
不支持,后台应用代码完成即可。多表约束 FOREIGN KEY 外键约束 外键让两个表的数据之间建立链接,保证数据的一致性和完整性 FOREIGN KEY ON UPDATE CASCADE 外键级联更新 FOREIGN KEY ON DELETE CASCADE 外键级联删除
1.3 主键约束
1.3.1 概念
主键
- 主键一般是表中记录的唯一标识,不参与业务逻辑(非业务字段)
- 一张表只能有一个主键;
主键约束 = 唯一约束 + 非空约束;
1.3.2 语法
添加约束
-- 创建表时添加主键约束(推荐方式)
CREATE TABLE 表名(
列名 数据类型 PRIMARY KEY [AUTO_INCREMENT],
…
);
CREATE TABLE 表名(
列名 数据类型,
[CONSTRAINT] [约束名称] PRIMARY KEY(列名)
); -- 建完表后添加主键约束
ALTER TABLE 表名 ADD PRIMARY KEY(字段名);
删除约束
ALTER TABLE 表名 DROP PRIMARY KEY;
1.3.3 演示代码
-- 删除表以免影响本次实验
DROP TABLE IF EXISTS student;
-- 创建学生表(编号、姓名、年龄) 编号设为主键 --- 推荐使用方式
CREATE TABLE student(
id INT PRIMARY KEY,
`name` VARCHAR(30),
age INT
);
-- 查询学生表的详细信息
DESC student;
-- 添加数据
INSERT INTO student VALUES (1,'张三',23);
INSERT INTO student VALUES (2,'李四',24);
-- 删除主键
ALTER TABLE student DROP PRIMARY KEY;
-- 建表后单独添加主键约束
ALTER TABLE student MODIFY id INT PRIMARY KEY;
1.4 主键自增约束
1.4.1 概念
主键自增 = 主键 + 自增
自增要求:字段本身必须是数字类型,且唯一。
注意事项:
- 为了保证数据安装性和一致性,主键自增时会自动规避掉已经“使用”的主键
- 使用:已经存在的主键值在删除后,添加但失败的记录,跳过的主键。
最佳实践:主键一般设置为:整型自增。
1.4.2 语法
添加约束
-- 创建表时添加主键约束(推荐方式)
CREATE TABLE 表名(
列名 数据类型 PRIMARY KEY AUTO_INCREMENT,
…
);
CREATE TABLE 表名(
列名 数据类型,
[CONSTRAINT] [约束名称] PRIMARY KEY(列名)
); -- 建完表后添加主键约束
ALTER TABLE 表名 ADD PRIMARY KEY(字段名);删除约束
ALTER TABLE 表名 DROP PRIMARY KEY;
1.4.3 演示代码
-- 删除表以免影响本次实验
DROP TABLE IF EXISTS student;
-- 创建学生表(编号、姓名、年龄) 编号设为主键自增
/*
int/bigint 自动增长
自增一般和其他键约束配合使用,最常用的是和主键一起配合使用
*/
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(30),
age INT
);
-- 查询学生表的详细信息
DESC student;
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23),(NULL,'李四',24);
-- 删除自增约束
ALTER TABLE student MODIFY id INT;
INSERT INTO student VALUES (NULL,'张三',23);
-- 建表后单独添加自增约束
ALTER TABLE student MODIFY id INT AUTO_INCREMENT;
1.5 唯一约束
1.5.1 概念
要求列中所有数据值均不相同 。如果添加重复的数据会报错并添加失败。
1.5.2 语法
添加约束
-- 创建表时添加唯一约束(推荐方式)
CREATE TABLE 表名(
列名 数据类型 UNIQUE [AUTO_INCREMENT],
-- AUTO_INCREMENT: 当不指定值时自动增长
…
);
CREATE TABLE 表名(
列名 数据类型,
…
[CONSTRAINT] [约束名称] UNIQUE(列名)
); -- 建完表后添加唯一约束
ALTER TABLE 表名 MODIFY 字段名 数据类型 UNIQUE;
删除约束
ALTER TABLE 表名 DROP INDEX 字段名;
1.5.3 演示代码
-- 删除表以免影响本次实验
DROP TABLE IF EXISTS student;
-- 创建学生表(编号、姓名、年龄) 编号设为主键自增,年龄设为唯一
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(30),
age INT UNIQUE
);
-- 查询学生表的详细信息
DESC student;
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23);
INSERT INTO student VALUES (NULL,'李四',23);
-- 删除唯一约束
ALTER TABLE student DROP INDEX age;
-- 建表后单独添加唯一约束
ALTER TABLE student MODIFY age INT UNIQUE;
1.6 非空约束
1.6.1 概念
要求列中所有数据值不能为NULL
。如果为NULL则报错并添加失败。
1.6.2 语法
添加约束
-- 创建表时添加非空约束(推荐方式)
CREATE TABLE 表名(
列名 数据类型 NOT NULL,
…
); -- 建完表后添加非空约束,如果字段中存在空值则无法添加成功
ALTER TABLE 表名 MODIFY 字段名 数据类型 NOT NULL;
删除约束
ALTER TABLE 表名 MODIFY 字段名 数据类型;
1.6.3 演示代码
-- 删除表以免影响本次实验
DROP TABLE IF EXISTS student;
-- 创建学生表(编号、姓名、年龄) 编号设为主键自增,姓名设为非空,年龄设为唯一
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
age INT UNIQUE
);
-- 查询学生表的详细信息
DESC student;
-- 添加数据,添加成功
INSERT INTO student VALUES (NULL,'张三',23);
-- 添加数据,添加失败,因为name列的值为空,违反了非空的约束。1048 - Column 'name' cannot be null
INSERT INTO student VALUES (NULL,NULL,24);
-- 删除非空约束
ALTER TABLE student MODIFY `name` VARCHAR(30);
INSERT INTO student VALUES (NULL,NULL,25);
-- 建表后单独添加非空约束,如果字段中存在空值则无法添加成功
ALTER TABLE student MODIFY `name` VARCHAR(30) NOT NULL;
-- 查看所有数据
SELECT * FROM student;
1.7 默认约束
1.7.1 概念
保存数据时,未指定值则采用默认值。
1.7.2 语法
添加约束
-- 创建表时添加默认约束(推荐方式)
CREATE TABLE 表名(
列名 数据类型 DEFAULT 默认值,
…
); -- 建完表后添加默认约束
ALTER TABLE 表名 ALTER 列名 SET DEFAULT 默认值;
删除约束
ALTER TABLE 表名 ALTER 列名 DROP DEFAULT;
1.8 演示案例
演示案例的需求:
-- 员工表
CREATE TABLE emp (
id INT, -- 员工id,主键且自增长
ename VARCHAR(50), -- 员工姓名,非空并且唯一
joindate DATE, -- 入职日期,非空
salary DOUBLE(7,2) , -- 工资,非空
bonus DOUBLE(7,2) -- 奖金,如果没有奖金默认为0
);
答案及验证
SQL
语句-- 建表前先删除,健壮性删除
DROP TABLE IF EXISTS emp; -- 员工表,建表时添加约束
CREATE TABLE emp (
id INT PRIMARY KEY auto_increment, -- 员工id,主键且自增长
ename VARCHAR(50) NOT NULL UNIQUE, -- 员工姓名,非空并且唯一
joindate DATE NOT NULL , -- 入职日期,非空
salary DOUBLE(7,2) NOT NULL , -- 工资,非空
bonus DOUBLE(7,2) DEFAULT 0 -- 奖金,如果没有奖金默认为0 ); INSERT INTO emp(id,ename,joindate,salary,bonus) values(1,'张三','1999-11-11',8800,5000); -- 演示主键约束:非空且唯一
INSERT INTO emp(id,ename,joindate,salary,bonus) values(null,'张三','1999-11-11',8800,5000); INSERT INTO emp(id,ename,joindate,salary,bonus) values(1,'张三','1999-11-11',8800,5000); INSERT INTO emp(id,ename,joindate,salary,bonus) values(2,'李四','1999-11-11',8800,5000); -- 演示非空约束
INSERT INTO emp(id,ename,joindate,salary,bonus) values(3,null,'1999-11-11',8800,5000); -- 演示唯一约束
INSERT INTO emp(id,ename,joindate,salary,bonus) values(3,'李四','1999-11-11',8800,5000); -- 演示默认约束
INSERT INTO emp(id,ename,joindate,salary) values(3,'王五','1999-11-11',8800); -- 不赋任何值,才会执行默认约束;NULL也不要赋值
INSERT INTO emp(id,ename,joindate,salary,bonus) values(4,'赵六','1999-11-11',8800,null); -- 演示自动增长:auto_increment:当列是数字类型并且 唯一约束
INSERT INTO emp(ename,joindate,salary,bonus) values('赵六','1999-11-11',8800,null);
INSERT INTO emp(id,ename,joindate,salary,bonus) values(null,'赵六2','1999-11-11',8800,null);
INSERT INTO emp(id,ename,joindate,salary,bonus) values(null,'赵六3','1999-11-11',8800,null); SELECT * from emp;
1.9 外键约束
1.9.1 概念
描述的是多表(记录)之间关系。
做法:
- 在A表中添加一个额外的字段(外键列),并让该字段指向了另外一张表B的主键。
- 含有外键列的A表是从表,另外一张表B是主表。
让两张表之间的记录产生关联关系,在新增和删除的时候,校验是否符合逻辑,已达到保证数据准确安全的目的。
校验是由mysql
(的事务)来完成,消耗一定的性能。
1.9.2 分类
外键分为 物理外键 和 逻辑外键
物理外键
有外键字段,并且使用
foreign key
在数据库层面关联表;数据库维护外键关系,保证数据安全。逻辑外键
有外键字段,但是没有使用foreign key
在数据库层面关联表,而是在后台程序中Java
代码维护外键关系
应用场景分析
互联网系统用户量大,并发度高。
物理外键需要数据库维护事物的特性,资源消耗大。数据库服务器不易扩展,数据库性能容易成为系统的瓶颈。
逻辑外键可以让数据库表的关系在后台项目代码内控制,让应用服务器承担此部分的压力,且应用服务器易拓展。传统行业软件项目并发量可控,数据量也一般不会超大。
物理外键可以借助数据库产品自身的特性实现表与关联表之间的数据一致性和更新,降低开发成本
逻辑外键会提高开发成本,降低开发效率和速度。
总结:物理外键适用于传统普通项目,逻辑外键适用于互联网大型项目。
1.9.3 语法及演示代码
-- 创建db2数据库
CREATE DATABASE db2;
-- 使用db2数据库
USE db2;
/*
外键约束
标准语法:
创建表时添加外键约束
CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主表主键列名)
*/
-- 删除表
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
-- 部门表
CREATE TABLE dept(
id int primary key auto_increment,
dep_name varchar(20),
addr varchar(20)
);
-- 员工表
CREATE TABLE emp(
id int primary key auto_increment,
name varchar(20),
age int,
dep_id int,
-- 添加外键 dep_id,关联 dept 表的id主键
CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES dept(id)
);
-- 添加 2 个部门
insert into dept(dep_name,addr) values
('研发部','广州'),('销售部', '深圳');
-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO emp (NAME, age, dep_id) VALUES
('张三', 20, 1),
('李四', 20, 1),
('王五', 20, 1),
('赵六', 20, 2),
('孙七', 22, 2),
('周八', 18, 2);
-- ------------------
select * from emp;
/*
删除外键约束
标准语法:
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
*/
-- 删除外键约束
alter table emp drop FOREIGN key fk_emp_dept;
/*
建表后单独添加外键约束
标准语法:
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);
*/
-- 添加外键约束
alter table emp add CONSTRAINT fk_emp_dept FOREIGN key(dep_id) REFERENCES dept(id);
2. 软件开发相关
2.1 软件开发步骤
2.2 数据库设计
官方概念:数据库设计就是根据业务系统的具体需求,结合我们所选用的DBMS,为这个业务系统构造出最优的数据存储模型。
通俗解释:建立数据库中的表结构以及表与表之间的关联关系的过程。
白话:
- 有哪些表?
- 表里有哪些字段?
- 表和表之间有什么关系?
2.3 数据库设计步骤
需求分析(数据是什么?数据具有哪些属性?数据与属性的特点是什么)
逻辑分析(通过
ER
图对数据库进行逻辑建模,不需要考虑我们所选用的数据库管理系统)如下图就是ER(Entity/Relation)图:
物理设计(根据数据库自身的特点把逻辑设计转换为物理设计)
维护设计(1.对新的需求进行建表;2.表优化)
3. 表关系
要求:
- 理解表关系
- 掌握不同表关系下的建表原则
3.1 概念
关系型数据库中,表与表之前存在各种联系。
多表之间的关系 本质上是 表中记录之间的关系。
这种联系分为三种情况:
- 一对多:A表中的一条记录,对应B表中的多条记录。
- 多对多:A表多条记录和B表中多条记录有关系。
- 一对一:A表中一个记录唯一对应B表中一个记录。反过来一样。
3.2 一对多
/*
一对多
A表中的一条记录,对应B表中的多条记录
建表原则
在多的表中添加一个额外字段,作为外键指向一的一方的主键。
*/
-- 删除表
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
-- 部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
dep_name VARCHAR(20),
addr VARCHAR(20)
);
-- 员工表
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
age INT,
dep_id INT,
-- 添加外键 dep_id,关联 dept 表的id主键
CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES dept(id)
);
-- 添加 2 个部门
insert INTo dept(dep_name,addr) values
('研发部','广州'),('销售部', '深圳');
-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO emp (NAME, age, dep_id) VALUES
('张三', 20, 1),
('李四', 20, 1),
('王五', 20, 1),
('赵六', 20, 2),
('孙七', 22, 2),
('周八', 18, 2);
-- ------------------
select * from emp;
/*
删除外键约束
标准语法:
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
*/
-- 删除外键约束
alter table emp drop FOREIGN key fk_emp_dept;
/*
建表后单独添加外键约束
标准语法:
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);
*/
-- 添加外键约束
alter table emp add CONSTRAINT fk_emp_dept FOREIGN key(dep_id) REFERENCES dept(id);
3.3 多对多
/*
多对多
A表多条记录和B表中多条记录有关系
建表原则
借助中间表,该表最少有两个字段,分别作为外键指向另外两张表的主键
从A、B表任意一表任意一条记录的角度出发,看中间表,都是一对多关系
多对多的关系可以成分多个一对多。
中间表建表经验
该表仅仅是作为中间表使用,没有任何业务逻辑在里面。这个表就是一个普普通通的中间表,表中只需要有两个外键,分别指向另外两张表的主键;两个外键加在一起建立一个联合主键:
利用两个外键作为该中间表的联合主键(多个列一起作为主键)使用
CREATE TABLE tb_order_goods (
order_id INT,
goods_id INT,
PRIMARY KEY (order_id,goods_id), -- 联合主键。两列何在一起,满足主键要求:唯一非空
CONSTRAINT `order_goods_fk_1` FOREIGN KEY (order_id) REFERENCES tb_order (id),
CONSTRAINT `order_goods_fk_2` FOREIGN KEY (goods_id) REFERENCES tb_goods (id)
)
如果该中间表中有其他业务字段,此时是该表一张业务表,就需要定义一个额外主键
增加一个字段,单独作为主键使用
CREATE TABLE tb_order_goods2 (
id INT,
order_id INT,
goods_id INT,
count INT, -- 业务字段
order_time DATATIME, -- 业务字段
CONSTRAINT `order_goods_fk_1` FOREIGN KEY (order_id) REFERENCES tb_order (id),
CONSTRAINT `order_goods_fk_2` FOREIGN KEY (goods_id) REFERENCES tb_goods (id)
)
*/
/*
多对多:
* 如:订单 和 商品
* 一个商品对应多个订单,一个订单包含多个商品
实现方式:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
*/
-- 删除表
DROP TABLE IF EXISTS tb_order_goods;
DROP TABLE IF EXISTS tb_order;
DROP TABLE IF EXISTS tb_goods;
-- 订单表
CREATE TABLE tb_order(
id INT PRIMARY KEY AUTO_INCREMENT,
payment DOUBLE(10,2),
payment_type TINYINT,
status TINYINT
);
-- 商品表
CREATE TABLE tb_goods(
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100),
price DOUBLE(10,2)
);
-- 订单商品中间表
CREATE TABLE tb_order_goods(
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT,
goods_id INT,
count INT
);
-- 建完表后,添加外键
alter table tb_order_goods add CONSTRAINT fk_order_id FOREIGN key(order_id) REFERENCES tb_order(id);
alter table tb_order_goods add CONSTRAINT fk_goods_id FOREIGN key(goods_id) REFERENCES tb_goods(id);
-- order表记录
INSERT INTO `tb_order` VALUES (1, 10000.00, 1, 1),(2, 30000.00, 1, 1);
-- goods表记录
INSERT INTO `tb_goods` VALUES (1, '手机', 3999.00), (2, '电脑', 5999.00);
-- 中间表记录
INSERT INTO `tb_order_goods` VALUES (1, 1, 1, 3),(2, 1, 2, 2),(3, 2, 1, 5),(4, 2, 2, 30);
3.4 一对一
/*
多表,一个系统中有多张数据库表
一对一:A表中一个记录唯一对应B表中一个记录。
建表原则:
外键唯一:在任意一个表中添加一个额外字段(外键)并且添加唯一约束,作为外键指定另外一张表中的主键。(优选)
主键对等:两张表使用相同主键。不是通过外键来维护的,是在后台Java程序中维护。
一对一主要用于表的拆分。
把一张字段众多的表中高频使用的字段拆分出来到一个新的表中,以提高高频数据的查询性能;这两个表是一对一关系。
eg:用户表和用户详情表;商品和商品详情表等等。
*/
TODO 表关系 表数据
3.5 案例
根据下图设计表及表和表之间的关系:
经过分析,我们分为 专辑表
曲目表
短评表
用户表
4张表。
一个专辑可以有多个曲目,一个曲目只能属于某一张专辑,所以专辑表和曲目表的关系是一对多。
一个专辑可以被多个用户进行评论,一个用户可以对多个专辑进行评论,所以专辑表和用户表的关系是 多对多。
一个用户可以发多个短评,一个短评只能是某一个人发的,所以用户表和短评表的关系是 一对多。
4. 多表联合查询
4.1 概念
多表联查:从多张表中一次性的查询出我们想要的数据。生产环境中的主流查询方式。
笛卡尔积:数学中的概念,简单的说就是两个集合相乘的结果。
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
在MySQL
中,A表有两条记录,B表有三条记录,那么笛卡尔积查询出来的结果就有2*3
条。
在多表联合查询时,我们可以通过设置条件等方式尽量消除笛卡尔积。
4.2 查询分类
连接查询
- 内连接查询 :相当于查询AB交集数据。可能会“查丢”数据。
- 外连接查询
- 左外连接查询 :相当于查询A表所有数据和AB交集部分数据
- 右外连接查询 : 相当于查询B表所有数据和AB交集部分数据
子查询(套娃)
- 把一个查询的结果作为另外一个查询的条件和虚拟表,参与查询。
4.3 数据准备
表关系模型图
建表语句
-- 如果表已存在,就删除,避免影响后续实验
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
-- 创建部门表
CREATE TABLE dept(
did INT PRIMARY KEY AUTO_INCREMENT,
dname VARCHAR(20)
);
-- 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dep_id INT,
FOREIGN KEY (dep_id) REFERENCES dept(did) -- 外键,关联部门表(部门表的主键)
);
-- 添加部门数据
INSERT INTO dept (dNAME) VALUES ('研发部'),('市场部'),('财务部'),('销售部');
-- 添加员工数据
INSERT INTO emp(NAME,gender,salary,join_date,dep_id) VALUES
('孙悟空','男',7200,'2013-02-24',1),
('猪八戒','男',3600,'2010-12-02',2),
('唐僧','男',9000,'2008-08-08',2),
('白骨精','女',5000,'2015-10-07',3),
('蜘蛛精','女',4500,'2011-03-14',1),
('小白龙','男',2500,'2011-02-14',null);
4.4 内连接查询
查询的是多个表之间有交集的记录,查询结果受表中数据间关系的影响可能不完整,所以不建议使用内连接查询。
/*
隐式内连接
标准语法:
SELECT 列名 FROM 表名1,表名2,表名3……N WHERE 多表之间的主外键对等条件 [AND 其他过滤条件];
*/
-- 隐式内连接
SELECT
*
FROM
emp,
dept
WHERE
emp.dep_id = dept.did;
-- 查询 emp的 name, gender,dept表的dname
SELECT
emp. NAME,
emp.gender,
dept.dname
FROM
emp,
dept
WHERE
emp.dep_id = dept.did;
-- 给表 起别名
SELECT
t1. NAME,
t1.gender,
t2.dname
FROM
emp t1,
dept t2
WHERE
t1.dep_id = t2.did;
/*
显示内连接
标准语法:
SELECT 列名 FROM 表名1 [INNER] JOIN 表名2 ON 主外键对等 [[INNER]JOIN 表名3 ON 主外键对等] [WHERE 其他[多个]条件];
*/
SELECT
*
FROM
emp
INNER JOIN
dept
ON
emp.dep_id = dept.did;
SELECT
*
FROM
emp
JOIN
dept
ON
emp.dep_id = dept.did;
4.5 外链接查询
- 很多时候的连接查询会有隐含的“所有”字样,要注意区分。
- 要查询某一张表的所有信息,就需要使用外连接。
/*
左/右外连接
标准语法:
SELECT 列名 FROM 表名1 LEFT|RIGHT [OUTER] JOIN 表名2 ON 主外键对等 [LEFT|RIGHT JOIN 表名3 ON 主外键对等] [WHERE 其他条件];
如果要查询出主表所有的符合条件是数据,我们一般使用外链接,因为内连接可能会丢失部分数据。
左外连接以左表为主表,右外连接以右边的表为主表;
只掌握一个即可,因为可以互换。调换一下主表和从表的位置即可。
*/
-- 左外连接
-- 查询emp表所有数据和对应的部门信息
SELECT
*
FROM
emp
LEFT JOIN
dept
ON
emp.dep_id = dept.did;
-- 右外连接
-- 查询dept表所有数据和对应的员工信息
SELECT
*
FROM
emp
RIGHT JOIN
dept
ON
emp.dep_id = dept.did;
SELECT
*
FROM
dept
LEFT JOIN
emp
ON
emp.dep_id = dept.did;
4.6 子查询
概念:
把第一次查询的结果作为第二次查询的条件/虚拟表 参与到第二次查询中,其中第一次查询就是一个子查询。
执行顺序:
子查询先执行,主查询后执行。
注意:
很多情况,子查询和内外连接查询时可以相互转换,而达到相同的效果
这个时候,优先使用内外连接查询,查询次数少,性能更高。根据子查询的结果不同,子查询在主查询中的角色不同,详情见下:
子查询结果 子查询特点 子查询在主查询中的角色 单行单列 单例 作为条件放在 where
后面,使用=、!=、>、<连接多行单列 单列 作为条件放在 where
后面,使用in()
单行多列 多列 作为 虚拟表
放在from
后面,通常会起别名多行多列 多列 作为 虚拟表
放在from
后面,通常会起别名演示代码
/*
子查询
把第一次查询的结果作为第二次查询的条件/虚拟表 参与到第二次查询中,其中第一次查询就是一个子查询。 子查询先执行,主查询后执行。 按照子查询的结果集不同,有不同的使用方式。子查询结果集为: 单行单列:作为条件,放在主查询的where后面
多行单列/单行单列:作为条件,放在主查询的where后面,使用 IN()
多行多列/单行多列:作为虚拟表,放在from后面,这种情况下,一般会为虚拟表起别名,方便使用
查询订单表中id大于4的订单信息和所属用户信息 注意:
很多情况,子查询和内外连接查询时可以相互转换 而达到相同的效果
这个时候,优先使用内外连接查询,查询次数少,性能更高。 标准语法:
SELECT 列名 FROM 表名 WHERE 列名=(SELECT 列名 FROM 表名 [WHERE 条件]);
*/ // TODO 演示代码
-- 查询工资高于猪八戒的员工信息 select * from emp; -- 1. 查询猪八戒的工资
select salary from emp where name = '猪八戒'; -- 2. 查询工资高于猪八戒的员工信息
select * from emp where salary > 3600; select * from emp where salary > (select salary from emp where name = '猪八戒'); -- 查询 '财务部' 和 '市场部' 所有的员工信息
-- 查询 '财务部' 所有的员工信息 select did from dept where dname = '财务部' or dname = '市场部'; select * from emp where dep_id in (select did from dept where dname = '财务部' or dname = '市场部'); -- 查询入职日期是 '2011-11-11' 之后的员工信息和部门信息
-- 查询入职日期是 '2011-11-11' 之后的员工信息 select * from emp where join_date > '2011-11-11' ; select * from (select * from emp where join_date > '2011-11-11' ) t1, dept where t1.dep_id = dept.did;
4.7 案例演示
4.7.1 需求
-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
-- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
-- 3.查询员工姓名,工资,工资等级
-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
-- 5.查询出部门编号、部门名称、部门位置、部门人数
4.7.2 准备数据
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
DROP TABLE IF EXISTS job;
DROP TABLE IF EXISTS salarygrade;
-- 部门表
CREATE TABLE dept (
id INT PRIMARY KEY PRIMARY KEY, -- 部门id
dname VARCHAR(50), -- 部门名称
loc VARCHAR(50) -- 部门所在地
);
-- 职务表,职务名称,职务描述
CREATE TABLE job (
id INT PRIMARY KEY,
jname VARCHAR(20),
description VARCHAR(50)
);
-- 员工表
CREATE TABLE emp (
id INT PRIMARY KEY, -- 员工id
ename VARCHAR(50), -- 员工姓名
job_id INT, -- 职务id
mgr INT , -- 上级领导
joindate DATE, -- 入职日期
salary DECIMAL(7,2), -- 工资
bonus DECIMAL(7,2), -- 奖金
dept_id INT, -- 所在部门编号
CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
);
-- 工资等级表
CREATE TABLE salarygrade (
grade INT PRIMARY KEY, -- 级别
losalary INT, -- 最低工资
hisalary INT -- 最高工资
);
-- 添加4个部门
INSERT INTO dept(id,dname,loc) VALUES
(10,'教研部','北京'),
(20,'学工部','上海'),
(30,'销售部','广州'),
(40,'财务部','深圳');
-- 添加4个职务
INSERT INTO job (id, jname, description) VALUES
(1, '董事长', '管理整个公司,接单'),
(2, '经理', '管理部门员工'),
(3, '销售员', '向客人推销产品'),
(4, '文员', '使用办公软件');
-- 添加员工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES
(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);
-- 添加5个工资等级
INSERT INTO salarygrade(grade,losalary,hisalary) VALUES
(1,7000,12000),
(2,12010,14000),
(3,14010,20000),
(4,20010,30000),
(5,30010,99990);
4.7.3 演示代码
-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
/*
分析:
1. 员工编号,员工姓名,工资 信息在emp 员工表中
2. 职务名称,职务描述 信息在 job 职务表中
3. job 职务表 和 emp 员工表 是 一对多的关系 。对等条件:emp.job_id = job.id
*/
-- 隐式内连接
SELECT
emp.id,
emp.ename,
emp.salary,
job.jname,
job.description
FROM
emp,
job
WHERE
emp.job_id = job.id;
SELECT
*
FROM
emp;
SELECT
*
FROM
job;
-- 显式内连接
SELECT
emp.id,
emp.ename,
emp.salary,
job.jname,
job.description
FROM
emp
INNER JOIN job ON emp.job_id = job.id;
-- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
/*
分析:
1. 员工编号,员工姓名,工资 信息在emp 员工表中
2. 职务名称,职务描述 信息在 job 职务表中
3. job 职务表 和 emp 员工表 是 一对多的关系。对等条件: emp.job_id = job.id
4. 部门名称,部门位置 来自于 部门表 dept
5. dept 和 emp 一对多关系。对等条件: dept.id = emp.dept_id
*/
-- 隐式内连接
SELECT
emp.id,
emp.ename,
emp.salary,
job.jname,
job.description,
dept.dname,
dept.loc
FROM
emp,
job,
dept
WHERE
emp.job_id = job.id
and dept.id = emp.dept_id
;
-- 显式内连接
SELECT
emp.id,
emp.ename,
emp.salary,
job.jname,
job.description,
dept.dname,
dept.loc
FROM
emp
INNER JOIN job ON emp.job_id = job.id
INNER JOIN dept ON dept.id = emp.dept_id
;
-- 3.查询员工姓名,工资,工资等级
/*
分析:
1. 员工姓名,工资 信息在emp 员工表中
2. 工资等级 信息在 salarygrade 工资等级表中
3. 对等条件:emp.salary >= salarygrade.losalary and emp.salary <= salarygrade.hisalary
*/
SELECT
emp.ename,
emp.salary,
t2.*
FROM
emp,
salarygrade t2
WHERE
emp.salary >= t2.losalary
AND emp.salary <= t2.hisalary
-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
/*
分析:
1. 员工编号,员工姓名,工资 信息在emp 员工表中
2. 职务名称,职务描述 信息在 job 职务表中
3. job 职务表 和 emp 员工表 是 一对多的关系 。对等条件:emp.job_id = job.id
4. 部门名称,部门位置 来自于 部门表 dept
5. dept 和 emp 一对多关系 dept.id = emp.dept_id
6. 工资等级 信息在 salarygrade 工资等级表中
7. 对等条件:emp.salary >= salarygrade.losalary and emp.salary <= salarygrade.hisalary
*/
SELECT
emp.id,
emp.ename,
emp.salary,
job.jname,
job.description,
dept.dname,
dept.loc,
t2.grade
FROM
emp
INNER JOIN job ON emp.job_id = job.id
INNER JOIN dept ON dept.id = emp.dept_id
INNER JOIN salarygrade t2 ON emp.salary BETWEEN t2.losalary and t2.hisalary;
-- 5.查询出部门编号、部门名称、部门位置、部门人数
/*
分析:
1. 部门编号、部门名称、部门位置 来自于部门 dept 表
2. 部门人数: 在emp表中 按照dept_id 进行分组,然后count(*)统计数量
3. 使用子查询,让部门表和分组后的表进行内连接
*/
select * from dept;
select dept_id, count(*) from emp group by dept_id;
SELECT
dept.id,
dept.dname,
dept.loc,
t1.count
FROM
dept,
(
SELECT
dept_id,
count(*) count
FROM
emp
GROUP BY
dept_id
) t1
WHERE
dept.id = t1.dept_id
5. 事务
5.1 概念
事务:本质上是数据库操作的一种安全机制
作用:
- 能保证一组对数据库的操作要么同时成功要么同时失败。
- 多个同时对数据库的操作尽量相互不受影响。
如果成功了,就表示提交了;如果失败了,就要回滚。
5.2 事务的操作
MySQL
中,默认是每个SQL
语句都自动开启事务,并在执行完之后,自动提交事务。如果要保证一组多个操作在一个事务中,那就需要我们自己手动控制事务。
START TRANSACTION / BEGIN:开启事务,在一组对数据库的操作开始之前开启事务。
ROLLBACK:回滚事务,该组操作结束前出了问题,为了保证数据准确,就需要回滚事务。
COMMIT:提交事务,整组操作过程中没有出任何问题,操作完整之后就可以提交事务,让记录的修改真正持久化到数据库中。
DROP TABLE IF EXISTS account;
-- 创建账户表
CREATE TABLE account(
id int PRIMARY KEY auto_increment,
name varchar(10),
money double(10,2)
);
-- 添加数据
INSERT INTO account(name,money) values('张三',1000),('李四',1000);
UPDATE account set money = 1000;
select * from account;
-- 开启事务
BEGIN;
-- 转账操作
-- 1. 查询李四账户金额是否大于500
-- 2. 李四账户 -500
UPDATE account set money = money - 500 where name = '李四';
-- 出现异常了...
-- 3. 张三账户 +500
UPDATE account set money = money + 500 where name = '张三';
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
-- 李四给张三转账500元
/*
try{
// 开启事务
// 转账操作1
// 出现问题
// 转账操作2
// 提交事务
}catch(Exception e){
// 回滚事务
// 出现问题之后,之后的代码便不会执行,也就是不会提交事务。
// 手动开启事务之后,事务必须手动提交之后才会永久保存到数据库。这时候,可以省略回滚。
}
*/
5.3 事务的特性
ACID
原子性(
Atomicity
)
当前事务下的一组操作是最小的操作单元,不能被拆分。一致性(
Consistency
)该事务操作前后,数据库内的数据总量保持一致。相对概念。
隔离性(
isolocation
)多个事务同时对数据的操作之间尽量相互不受影响。
持久性(
durability
)事务一旦提交,该事物中对数据库的修改操作,必须要能够持久化(保存到硬盘)。
5.4 事务的提交方式
自动提交(默认的方式):每个SQL
语句,执行前都会自己开一个事务,执行完就自动提交了。
手动提交:把自动提交改成手动提交,这时,所有对数据库的修改必须手动commit
之后才能最终保存。
设置成手动提交的两种方式:
- 修改全局变量
@@AUTOCOMMIT = 0
(0表示手动提交,1表示自动提交<默认值>) - 手动开启事务,
START TRANSACTION / BEGIN
。开启事务后,事务不会自动提交,需要手动提交。
注意:通过全局变量修改提交方式的做法比较危险,不推荐这么做。
第二种做法也是工作中常用的做法。
JavaWEB-02-MySQL高级的更多相关文章
- 2.mysql高级查询
01.SQL高级查询_排序 1.排序语句:order by 排序字段名 asc(默认的-升序) / desc(降序); 2.例如:查询所有服装类商品,将查询结果以价格升序排序: ...
- Mysql 高级部分
MySQL 高级部分 (1)索引(index)..................................................................... 1 (2) ...
- 「 MySQL高级篇 」MySQL索引原理,设计原则
大家好,我是melo,一名大二后台练习生,大年初三,我又来充当反内卷第一人了!!! 专栏引言 MySQL,一个熟悉又陌生的名词,早在学习Javaweb的时候,我们就用到了MySQL数据库,在那个阶段, ...
- MySQL高级(进阶)SQL语句
MySQL高级(进阶)SQL语句 目录 MySQL高级(进阶)SQL语句 一.实例准备--制表 1. 表1(商店区域表) 2. 表2(商店销售表) 3. 表3(城市表) 4. 表4(total_sal ...
- 「MySQL高级篇」MySQL索引原理,设计原则
大家好,我是melo,一名大二后台练习生,大年初三,我又来充当反内卷第一人了!!! 专栏引言 MySQL,一个熟悉又陌生的名词,早在学习Javaweb的时候,我们就用到了MySQL数据库,在那个阶段, ...
- mysql笔记04 MySQL高级特性
MySQL高级特性 1. 分区表:分区表是一种粗粒度的.简易的索引策略,适用于大数据量的过滤场景.最适合的场景是,在没有合适的索引时,对几个分区进行全表扫描,或者是只有一个分区和索引是热点,而且这个分 ...
- Mysql高级之权限检查原理
原文:Mysql高级之权限检查原理 用户进行数据库操作分为两步: 1 是否有权限连接,根据host,name,password: 2 是否有权限进行CURD: 图示解说: 关于用户权限在哪里进行存放? ...
- Mysql高级之触发器
原文:Mysql高级之触发器 触发器是一类特殊的事务 ,可以监视某种数据操作(insert/update/delete),并触发相关操作(insert/update/delete). 看以下事件: 完 ...
- Mysql高级之事务
原文:Mysql高级之事务 通俗的说事务: 指一组操作,要么都成功执行,要么都不执行.---->原子性 在所有的操作没有执行完毕之前,其他会话不能够看到中间改变的过程-->隔离性 事务发生 ...
- Mysql高级之索引
原文:Mysql高级之索引 索引:是针对数据所建立的目录. 作用: 可以加快查询速度 负面影响: 降低了增删改的速度. 索引的创建原则: 1:不要过度索引 2:在where条件最频繁的列上加.在重复度 ...
随机推荐
- 3.2 常用Linux命令
1.ifconfig命令 ifconfig命令用于获取网卡配置与网络状态等信息,英文全称为"interface config",语法格式为"ifconfig [参数] [ ...
- Spring从入门到源码(一)
Spring 1.什么是框架? 人话就是:方便干活,架子有了,直接拿来用就完事了. spring,springmvc,mybatis三大开框架 2.架构的演变过程 单一应用架构 垂直应用架构 分布式服 ...
- vite创建vue3+ts项目流程
vite+vue3+typescript搭建项目过程 vite和vue3.0都出来一段时间了,尝试一下搭vite+vue3+ts的项目 相关资料网址 vue3.0官网:https://v3.vue ...
- mybatis混淆概念
1.resultMap与resultType <mapper namespace="com.dao.FilmMapper"> <resultMap id=&quo ...
- 解决mysq服务无法正常启动问题
在mysql的启动过程中,遇到什么问题都可以反馈给我,我都会尽力帮你们解决 第一种:通过net start mysql启动MySQL服务器时,出现以下信息 是因为在MySQL5.7以上的版本中默认的没 ...
- 好客租房41-react组件基础综合案例-渲染列表数据
1渲染列表 在state定义数据 进行数据渲染 //导入react import React from 'react' import ReactDOM from 'react-dom' //导入组件 ...
- 实践torch.fx第一篇——基于Pytorch的模型优化量化神器
第一篇--什么是torch.fx 今天聊一下比较重要的torch.fx,也趁着这次机会把之前的torch.fx笔记整理下,笔记大概拆成三份,分别对应三篇: 什么是torch.fx 基于torch.fx ...
- 【单片机】CH32V103C8T6定时器3程序实验
代码功能:每隔1毫秒进入一次定时器中断. 每隔1秒串口打印一次数据. time.c #include "time.h" #include "ch32v10x.h" ...
- 解决 AMD 笔记本不插电源时屏幕偏暗的问题
办法:关掉显卡设置里的 Vari-Bright 选项 最近换了锐龙版的笔记本,用着还不错,就是不插电源时看屏幕亮度不太适应,整体偏暗,有点费眼,差点就觉得 AMD 不 Yes 了.然后网上一顿找,发现 ...
- (干货)基于 veImageX 搭建海报生成平台 -- 附源码
前言 618 年中促销即将来临,很多公司都会通过海报来宣传自己的促销方案,通常情况下海报由设计团队基于 PS.Sketch 等工具创作,后期若想替换海报文案.商品列表等内容则需打开原工程进行二次创作, ...