目录

1. 多表查询

1.1 概述

1.1.1 数据准备

1.1.2 介绍

1.1.3 分类

1.2 内连接

1.2.1 语法

1.2.2 案例演示

1.3 外连接

1.3.1 语法

1.3.2 案例演示

1.4 子查询

1.4.1 介绍

1.4.2 标量子查询

1.4.3 列子查询

1.4.4 行子查询

1.4.5 表子查询

1.5 案例

1.5.1 介绍

1.5.2 数据准备

1.5.3 需求实现

2. 事务

问题思考

2.1 介绍

2.2 操作

2.3 四大特性


1. 多表查询

1.1 概述

1.1.1 数据准备

执行如下脚本,创建emp表与dept表并插入测试数据。

-- 部门管理
create table dept(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(10) not null unique comment '部门名称',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '修改时间'
) comment '部门表';

insert into dept (id, name, create_time, update_time) values(1,'学工部',now(),now()),(2,'教研部',now(),now()),(3,'咨询部',now(),now()), (4,'就业部',now(),now()),(5,'人事部',now(),now());



-- 员工管理(带约束)
create table emp (
  id int unsigned primary key auto_increment comment 'ID',
  username varchar(20) not null unique comment '用户名',
  password varchar(32) default '123456' comment '密码',
  name varchar(10) not null comment '姓名',
  gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
  image varchar(300) comment '图像',
  job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
  entrydate date comment '入职时间',
  dept_id int unsigned comment '部门ID',
  create_time datetime not null comment '创建时间',
  update_time datetime not null comment '修改时间'
) comment='员工表';

INSERT INTO emp
	(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
	(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
	(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
	(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
	(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
	(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
	(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
	(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
	(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
	(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
	(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
	(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
	(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
	(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
	(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
	(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
	(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2007-01-01',2,now(),now()),
	(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());

dept表共5条记录,emp表共17条记录。

1.1.2 介绍
 

多表查询就是指从多张表中查询数据。
 

原来查询单表数据,执行的SQL形式为:select * from emp;

那么我们要执行多表查询,就只需要使用逗号分隔多张表即可,如: select * from emp , dept ; 具体的执行结果如下:
 

mysql查询多个表的单个字段数据命令_mysql

此时,我们看到查询结果中包含了大量的结果集,总共85条记录,而这其实就是员工表emp所有的记录(17) 与 部门表dept所有记录(5) 的所有组合情况,这种现象称之为笛卡尔积。接下来,就来简单介绍下笛卡尔积。

笛卡尔积: 笛卡尔乘积是指在数学中,两个集合A集合 和 B集合的所有组合情况。

mysql查询多个表的单个字段数据命令_子查询_02

而在多表查询中,我们是需要消除无效的笛卡尔积的,只保留两张表关联部分的数据。

mysql查询多个表的单个字段数据命令_子查询_03

mysql查询多个表的单个字段数据命令_sql_04

在SQL语句中,如何来去除无效的笛卡尔积呢? 我们可以给多表查询加上连接查询的条件即可。

select * from emp , dept where emp.dept_id = dept.id;

mysql查询多个表的单个字段数据命令_mysql_05

而由于id为17的员工,没有dept_id字段值,所以在多表查询时,根据连接查询的条件并没有查询到。

1.1.3 分类

  • 连接查询
  • 内连接:相当于查询A、B交集部分数据
  • 外连接:
  • 左外连接:查询左表所有数据,以及两张表交集部分数据
  • 右外连接:查询右表所有数据,以及两张表交集部分数据
  • 自连接:当前表与自身的连接查询,自连接必须使用表别名
  • 子查询

mysql查询多个表的单个字段数据命令_子查询_06

1.2 内连接

内连接查询的是两张表交集部分的数据。(也就是 A∩B 部分的数据)

mysql查询多个表的单个字段数据命令_sql_07

1.2.1 语法

内连接的语法分为两种: 隐式内连接、显式内连接。先来学习一下具体的语法结构。

1). 隐式内连接

select  字段列表   from   表1 , 表2   where   条件 ... ;

2). 显式内连接

select  字段列表   from   表1  [ inner ]  join 表2  on  连接条件 ... ;

1.2.2 案例演示

A. 查询每一个员工的姓名 , 及关联的部门的名称 (隐式内连接实现)
表结构: emp , dept
连接条件: emp.dept_id = dept.id

select emp.name , dept.name from emp , dept where emp.dept_id = dept.id ;

-- 为每一张表起别名,简化SQL编写
select e.name,d.name from emp e , dept d where e.dept_id = d.id;

B. 查询每一个员工的姓名 , 及关联的部门的名称 (显式内连接实现) --- inner join ... on...
表结构: emp , dept
连接条件: emp.dept_id = dept.id

select e.name, d.name from emp e inner join dept d  on e.dept_id = d.id;

-- 为每一张表起别名,简化SQL编写
select e.name, d.name from emp e join dept d  on e.dept_id = d.id;

表的别名:

①. tableA as 别名1 , tableB as 别名2 ;

②. tableA 别名1 , tableB 别名2 ;

注意事项:

一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。

1.3 外连接

mysql查询多个表的单个字段数据命令_mysql查询多个表的单个字段数据命令_08

1.3.1 语法

外连接分为两种,分别是:左外连接 和 右外连接。具体的语法结构为:
 

1). 左外连接

select  字段列表   from   表1  left  [ outer ]  join 表2  on  条件 ... ;

左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。

2). 右外连接

select  字段列表   from   表1  right  [ outer ]  join 表2  on  条件 ... ;

右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。

1.3.2 案例演示
 

A. 查询员工表 所有 员工的姓名, 和对应的部门名称 (左外连接)

由于需求中提到,要查询emp的所有数据,所以是不能用内连接查询的,需要考虑使用外连接查询。
 

表结构: emp, dept

连接条件: emp.dept_id = dept.id

select e.*, d.name from emp e left outer join dept d on e.dept_id = d.id;

select e.*, d.name from emp e left join dept d on e.dept_id = d.id;

B. 查询员工表 所有 部门的名称, 和对应的员工名称 (右外连接)

由于需求中提到,要查询dept表的所有数据,所以是不能用内连接查询的,需要考虑使用外连接查询。

表结构: emp, dept
 

连接条件: emp.dept_id = dept.id
 

select d.*, e.* from emp e right outer join dept d on e.dept_id = d.id;

select d.*, e.* from dept d left outer join emp e on e.dept_id = d.id;

注意事项:

左外连接和右外连接是可以相互替换的,只需要调整在连接查询时SQL中,表结构的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。

1.4 子查询

1.4.1 介绍
 

1). 概念

SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。

SELECT  *  FROM   t1   WHERE  column1 =  ( SELECT  column1  FROM  t2 );

子查询外部的语句可以是INSERT / UPDATE / DELETE / SELECT 的任何一个。

2). 分类
 

根据子查询结果不同,分为:
 

A. 标量子查询(子查询结果为单个值)
 

B. 列子查询(子查询结果为一列)

C. 行子查询(子查询结果为一行)
 

D. 表子查询(子查询结果为多行多列)

根据子查询位置,分为:

A. WHERE之后

B. FROM之后

C. SELECT之后

1.4.2 标量子查询

子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。
 

常用的操作符:= <> > >= < <=

案例:

A. 查询 "教研部" 的所有员工信息

完成这个需求时,我们可以将需求分解为两步:

①. 查询 "教研部" 部门ID

select id from dept where name = '教研部';

②. 根据 "教研部" 部门ID, 查询员工信息

select * from emp 
    where dept_id = (
    select id from dept
         where name = '教研部'
    );

B. 查询在 "方东白" 入职之后的员工信息

完成这个需求时,我们可以将需求分解为两步:

①. 查询 方东白 的入职日期

select entrydate from emp where name = '方东白';

②. 查询指定入职日期之后入职的员工信息

select * 
    from emp 
    where entrydate > (
        select entrydate from emp 
        where name = '方东白'
    );

1.4.3 列子查询

子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。
 

常用的操作符:IN 、NOT IN

操作符

描述

IN

在指定的集合范围之内,多选一

NOT IN

不在指定的集合范围之内

案例:
 

A. 查询 "教研部" 和 "咨询部" 的所有员工信息
 

分解为以下两步:
 

①. 查询 "销售部" 和 "市场部" 的部门ID

select id from dept where name = '销售部' or name = '市场部';

②. 根据部门ID, 查询员工信息

select * 
    from emp 
    where dept_id in (
        select id from dept 
        where name = '销售部' or name = '市场部'
    );

1.4.4 行子查询

子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。

常用的操作符:= 、<> 、IN 、NOT IN

案例:

A. 查询与 "韦一笑" 的入职日期 及 职位都相同的员工信息 ;

这个需求同样可以拆解为两步进行:

①. 查询 "韦一笑" 的入职日期 及 职位
 

select entrydate , job from emp where name = '韦一笑';

②. 查询与 "鹿杖客" 的薪资 及 职位相同的员工信息 ;

select * 
    from emp 
    where (entrydate,job) = (select entrydate , job from emp where name = '韦一笑');

1.4.5 表子查询

子查询返回的结果是多行多列,常作为临时表,这种子查询称为表子查询。
 

常用的操作符:IN

案例:

A. 查询入职日期是 "2006-01-01" 之后的员工信息 , 及其部门信息

分解为两步执行:
 

①. 入职日期是 "2006-01-01" 之后的员工信息

select * from emp where entrydate > '2006-01-01';

②. 查询这部分员工, 对应的部门信息;

select e.*, d.* 
    from (select * from emp where entrydate > '2006-01-01') e left join dept d 
    on e.dept_id = d.id ;

1.5 案例
 

1.5.1 介绍
 

案例中是瑞吉点餐项目部分的表结构,包括:分类表、菜品表、套餐表、套餐菜品关系表。具体的表结构关系如下:
 

mysql查询多个表的单个字段数据命令_子查询_09

1.5.2 数据准备
 

执行如下SQL脚本,导入测试数据:
 

-- 分类表
create table category(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(20) not null unique comment '分类名称',
    type tinyint unsigned not null comment '类型 1 菜品分类 2 套餐分类',
    sort tinyint unsigned not null comment '顺序',
    status tinyint unsigned not null default 0 comment '状态 0 禁用,1 启用',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '更新时间'
) charset utf8;

-- 菜品表
create table dish(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(20) not null unique comment '菜品名称',
    category_id int unsigned not null comment '菜品分类ID',
    price decimal(8, 2) not null comment '菜品价格',
    image varchar(300) not null comment '菜品图片',
    description varchar(200) comment '描述信息',
    status tinyint unsigned not null default 0 comment '状态, 0 停售 1 起售',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '更新时间'
) charset utf8;

-- 套餐表
create table setmeal(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(20) not null unique comment '套餐名称',
    category_id int unsigned not null comment '分类id',
    price decimal(8, 2) not null comment '套餐价格',
    image varchar(300) not null comment '图片',
    description varchar(200) comment '描述信息',
    status tinyint unsigned not null default 0 comment '状态 0:停用 1:启用',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '更新时间'
)charset utf8;

-- 套餐菜品关联表
create table setmeal_dish(
    id int unsigned primary key auto_increment comment '主键ID',
    setmeal_id int unsigned not null comment '套餐id ',
    dish_id int unsigned not null comment '菜品id',
    copies tinyint unsigned not null comment '份数'
)charset utf8;

-- ================================== 导入测试数据 ====================================
-- category
insert into category (id, type, name, sort, status, create_time, update_time) values (1, 1, '酒水饮料', 10, 1, '2022-08-09 22:09:18', '2022-08-09 22:09:18');
insert into category (id, type, name, sort, status, create_time, update_time) values (2, 1, '传统主食', 9, 1, '2022-08-09 22:09:32', '2022-08-09 22:18:53');
insert into category (id, type, name, sort, status, create_time, update_time) values (3, 2, '人气套餐', 12, 1, '2022-08-09 22:11:38', '2022-08-10 11:04:40');
insert into category (id, type, name, sort, status, create_time, update_time) values (4, 2, '商务套餐', 13, 1, '2022-08-09 22:14:10', '2022-08-10 11:04:48');
insert into category (id, type, name, sort, status, create_time, update_time) values (5, 1, '经典川菜', 6, 1, '2022-08-09 22:17:42', '2022-08-09 22:17:42');
insert into category (id, type, name, sort, status, create_time, update_time) values (6, 1, '新鲜时蔬', 7, 1, '2022-08-09 22:18:12', '2022-08-09 22:18:28');
insert into category (id, type, name, sort, status, create_time, update_time) values (7, 1, '汤类', 11, 1, '2022-08-10 10:51:47', '2022-08-10 10:51:47');

-- dish
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (1,'王老吉', 1, 6.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/41bfcacf-7ad4-4927-8b26-df366553a94c.png', '', 1, '2022-06-09 22:40:47', '2022-06-09 22:40:47');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (2,'北冰洋', 1, 4.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/4451d4be-89a2-4939-9c69-3a87151cb979.png', '还是小时候的味道', 1, '2022-06-10 09:18:49', '2022-06-10 09:18:49');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (3,'雪花啤酒', 1, 4.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/bf8cbfc1-04d2-40e8-9826-061ee41ab87c.png', '', 1, '2022-06-10 09:22:54', '2022-06-10 09:22:54');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (4,'米饭', 2, 2.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/76752350-2121-44d2-b477-10791c23a8ec.png', '精选五常大米', 1, '2022-06-10 09:30:17', '2022-06-10 09:30:17');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (5,'馒头', 2, 1.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/475cc599-8661-4899-8f9e-121dd8ef7d02.png', '优质面粉', 1, '2022-06-10 09:34:28', '2022-06-10 09:34:28');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (6,'老坛酸菜鱼', 5, 56.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/4a9cefba-6a74-467e-9fde-6e687ea725d7.png', '原料:汤,草鱼,酸菜', 1, '2022-06-10 09:40:51', '2022-06-10 09:40:51');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (7,'经典酸菜鮰鱼', 5, 66.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/5260ff39-986c-4a97-8850-2ec8c7583efc.png', '原料:酸菜,江团,鮰鱼', 1, '2022-06-10 09:46:02', '2022-06-10 09:46:02');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (8,'蜀味水煮草鱼', 5, 38.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/a6953d5a-4c18-4b30-9319-4926ee77261f.png', '原料:草鱼,汤', 1, '2022-06-10 09:48:37', '2022-06-10 09:48:37');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (9,'清炒小油菜', 6, 18.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/3613d38e-5614-41c2-90ed-ff175bf50716.png', '原料:小油菜', 1, '2022-06-10 09:51:46', '2022-06-10 09:51:46');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (10,'蒜蓉娃娃菜', 6, 18.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/4879ed66-3860-4b28-ba14-306ac025fdec.png', '原料:蒜,娃娃菜', 1, '2022-06-10 09:53:37', '2022-06-10 09:53:37');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (11,'清炒西兰花', 6, 18.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/e9ec4ba4-4b22-4fc8-9be0-4946e6aeb937.png', '原料:西兰花', 1, '2022-06-10 09:55:44', '2022-06-10 09:55:44');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (12,'炝炒圆白菜', 6, 18.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/22f59feb-0d44-430e-a6cd-6a49f27453ca.png', '原料:圆白菜', 1, '2022-06-10 09:58:35', '2022-06-10 09:58:35');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (13,'清蒸鲈鱼', 5, 98.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/c18b5c67-3b71-466c-a75a-e63c6449f21c.png', '原料:鲈鱼', 1, '2022-06-10 10:12:28', '2022-06-10 10:12:28');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (14,'东坡肘子', 5, 138.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/a80a4b8c-c93e-4f43-ac8a-856b0d5cc451.png', '原料:猪肘棒', 1, '2022-06-10 10:24:03', '2022-06-10 10:24:03');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (15,'梅菜扣肉', 5, 58.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/6080b118-e30a-4577-aab4-45042e3f88be.png', '原料:猪肉,梅菜', 1, '2022-06-10 10:26:03', '2022-06-10 10:26:03');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (16,'剁椒鱼头', 5, 66.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/13da832f-ef2c-484d-8370-5934a1045a06.png', '原料:鲢鱼,剁椒', 1, '2022-06-10 10:28:54', '2022-06-10 10:28:54');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (17,'馋嘴牛蛙', 5, 98.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/7a55b845-1f2b-41fa-9486-76d187ee9ee1.png', '配料:鲜活牛蛙,丝瓜,黄豆芽', 1, '2022-06-10 10:37:52', '2022-06-10 10:37:52');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (18,'鸡蛋汤', 7, 4.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/c09a0ee8-9d19-428d-81b9-746221824113.png', '配料:鸡蛋,紫菜', 1, '2022-06-10 10:54:25', '2022-06-10 10:54:25');
insert into dish (id, name, category_id, price, image, description, status, create_time, update_time) values (19,'平菇豆腐汤', 7, 6.00, 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/16d0a3d6-2253-4cfc-9b49-bf7bd9eb2ad2.png', '配料:豆腐,平菇', 1, '2022-06-10 10:55:02', '2022-06-10 10:55:02');

-- setmeal
insert into setmeal (id, category_id, name, price, status, description, image, create_time, update_time) values (1, 4, '商务套餐A', 20.00, 1, '', 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/21a5ed3a-97f6-447a-af9d-53deabfb5661.png', '2022-06-10 10:58:09', '2022-06-10 10:58:09');
insert into setmeal (id, category_id, name, price, status, description, image, create_time, update_time) values (2, 4, '商务套餐B', 22.00, 1, '', 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/8d0075f8-9008-4390-94ca-2ca631440304.png', '2022-06-10 11:00:13', '2022-06-10 11:11:37');
insert into setmeal (id, category_id, name, price, status, description, image, create_time, update_time) values (3, 3, '人气套餐A', 49.00, 1, '', 'https://reggie-itcast.oss-cn-beijing.aliyuncs.com/8979566b-0e17-462b-81d8-8dbace4138f4.png', '2022-06-10 11:11:23', '2022-06-10 11:11:23');

-- setmeal_dish
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (1, 1, 1, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (2, 1, 4, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (3, 1, 11, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (4, 2, 2, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (5, 2, 4, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (6, 2, 9, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (7, 3, 2, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (8, 3, 6, 1);
insert into setmeal_dish (id, setmeal_id, dish_id, copies) values (9, 3, 5, 1);

1.5.3 需求实现

  1. 查询价格低于 10元 的菜品的名称 、价格 及其 菜品的分类名称 .
select d.name, d.price, c.name 
    from dish d , category c 
    where d.category_id = c.id 
    and d.price < 10;
  1. 查询所有价格在 10元(含)到50元(含)之间 且 状态为'起售'的菜品名称、价格 及其 菜品的分类名称 (即使菜品没有分类 , 也需要将菜品查询出来).
select d.name , d.price , c.name 
    from dish d left join category c 
    on d.category_id = c.id 
    where d.price between 10 and 50 
    and d.status = 1;
  1. 查询每个分类下最贵的菜品, 展示出分类的名称、最贵的菜品的价格 .
select c.name , max(d.price) 
    from dish d , category c
    where d.category_id = c.id group by c.name;
  1. 查询各个分类下 状态为 '起售' , 并且 该分类下菜品总数量大于等于3 的 分类名称 .
select c.name , count(*) 
    from dish d , category c 
    where d.category_id = c.id 
    and d.status = 1 
    group by c.name 
    having count(*) >= 3;
  1. 查询出 "商务套餐A" 中包含了哪些菜品 (展示出套餐名称、价格, 包含的菜品名称、价格、份数).
select s.name, s.price, d.name , d.price, sd.copies 
    from setmeal s , setmeal_dish sd , dish d 
    where s.id = sd.setmeal_id 
    and sd.dish_id = d.id 
    and s.name = '商务套餐A';
  1. 查询哪些套餐中包含的有 "北冰洋" 汽水 (展示出套餐名称, 套餐价格).
select s.name , s.price 
    from setmeal s , setmeal_dish sd , dish d 
    where s.id = sd.setmeal_id 
    and sd.dish_id = d.id 
    and d.name = '北冰洋';
  1. 查询出低于菜品平均价格的菜品信息 (展示出菜品名称、菜品价格).
select * 
    from dish 
    where price < (
        select avg(price) from dish 
    );
  1. 查询出与 "剁椒鱼头" 的分类 及 价格都相同的菜品数据 .
select * from dish 
    where (category_id,price) = (
        select category_id , price 
        from dish 
        where name = '剁椒鱼头'
     );

2. 事务

问题思考
 

  • 场景:学工部 整个部门解散了,该部门及部门下的员工都需要删除了。
  • 操作:
-- 删除学工部
delete from dept where id = 1;

... -- 模拟错误

-- 删除学工部的员工
delete from emp where dept_id = 1;
  • 问题:如果删除部门成功了,而删除该部门的员工时,失败了,此时就造成了数据的不一致。

要解决上述的问题,就需要通过数据库中的 事务 来解决。

2.1 介绍
 

事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
 

比如,我们上述的业务中要求:解散部门。此时我们就需要删除该部门,并且删除该部门下的所有员工数据。 那这就是一组操作,要么全部成功,要么全部失败。

  • 正常情况:
     

程序正常执行,删除部门信息成功,删除该部门下的员工信息成功。

-- 删除学工部
delete from dept where id = 1;

-- 删除学工部的员工
delete from emp where dept_id = 1;
  • 异常情况

程序执行出错,删除部门信息成功,删除该部门下的员工信息失败了。 此时就出现问题了,原因是因为我们并未进行事务控制。

-- 删除学工部
delete from dept where id = 1;

...

-- 删除学工部的员工
delete from emp where dept_id = 1;

为了解决上述的问题,就需要通过数据的事务来完成,我们只需要在业务逻辑执行之前开启事务,执行完毕后提交事务。如果执行过程中报错,则回滚事务,把数据恢复到事务开始之前的状态。

默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句时,MySQL会立即隐式的提交事务。

2.2 操作
 

1). 开启事务

START  TRANSACTION   或  BEGIN ;

2). 提交事务

COMMIT;

3). 回滚事务

ROLLBACK;

此时,我们就可以在删除部门,并删除该部门下的员工时,进行事务控制了:

上述的这组SQL语句,如果如果执行成功,则提交事务,执行如下语句:
 

上述的这组SQL语句,如果如果执行失败,则回滚事务,执行如下语句:
 

2.3 四大特性

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  • 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

上述就是事务的四大特性,简称ACID。