(旧笔记2)MySQL
多表查询
-- 准备数据: 以下练习将使用db30库中的表及表记录,请先进入db30数据库!!!
连接查询
-- 42.查询部门和部门对应的员工信息
select * from dept,emp;
上面的查询中存在大量错误的数据,一般我们不会直接使用这种查询。
笛卡尔积查询:所谓笛卡尔积查询就是指,查询两张表,其中一张表有m条记录,另一张表有n条记录,查询的结果是m*n条。
-- 员工所属的部门编号,等于部门的编号
select * from dept,emp
where emp.dept_id=dept.id;
通过where子句将笛卡尔积查询中的错误数据剔除,保留正确的数据,这就是连接查询!
上面的查询可以换成下面的查询:
select * from dept inner join emp
on emp.dept_id=dept.id; -- 内连接查询,和上面的查询结果一样。
左外连接查询
-- 43.查询【所有部门】及部门对应的员工,如果某个部门下没有员工,员工显示为null
select * from dept left join emp
on emp.dept_id=dept.id;

左外连接查询:可以将左边表中的所有记录都查询出来,右边表只显示和左边相对应的数据,如果左边表中某些记录在右边没有对应的数据,右边显示为null即可。
右外连接查询
-- 44.查询【所有员工】及员工所属的部门,如果某个员工没有所属部门,部门显示为null即可
select * from dept right join emp
on emp.dept_id=dept.id;

右外连接查询:可以将右边表中的所有记录都查询出来,左边表只显示和右边相对应的数据,如果右边表中某些记录在左边没有对应的数据,可以显示为null。
select * from dept left join emp on emp.dept_id=dept.id
union
select * from dept right join emp on emp.dept_id=dept.id;
可以使用union将左外连接查询的结果和右外连接查询的结果合并在一起,并去除重复的记录。例如:

需要注意的是:union可以将两条SQL语句执行的结果合并,但是有前提:
(1)两条SQL语句查询的结果列数必须一致
(2)两条SQL语句查询的结果列名、顺序也必须一致
并且union默认就会将两个查询中重复的记录去除(如果不希望去除重复记录,可以使用union all)
子查询练习
-- 准备数据:以下练习将使用db40库中的表及表记录,请先进入db40数据库!!!
-- 45.列出薪资比'王海涛'的薪资高的所有员工,显示姓名、薪资
-- 求出‘王海涛’的薪资
select sal from emp where name='王海涛'; -- 2450
-- 求出比'王海涛'薪资高的所有员工信息
select name,sal from emp
where sal>(select sal from emp where name='王海涛');
-- 46.列出与'刘沛霞'从事相同职位的所有员工,显示姓名、职位。
-- 求出'刘沛霞'从事的职位
select job from emp where name='刘沛霞';
-- 求出和‘刘沛霞’从事相同职位的员工
select name,job from emp
where job=(select job from emp where name='刘沛霞');
-- 47.列出薪资比'大数据部'部门(已知部门编号为30)所有员工薪资都高的员工信息,显示员工姓名、薪资和部门名称。
如果不考虑没有部门的员工
-- 先连接查询部门表和员工表
select emp.name,sal,dept.name from dept,emp
where emp.dept_id=dept.id;
-- 求出‘大数据’部门的最高薪资
select max(sal) from emp where dept_id=30;
-- 列出薪资比 ‘大数据’部门最高薪资还高的员工信息
select emp.name,sal,dept.name from dept,emp
where emp.dept_id=dept.id and
sal > (select max(sal) from emp where dept_id=30);
如果加上没有部门的员工
-- 使用外连接查询部门表和员工表
select emp.name,sal,dept.name from dept right join emp
on emp.dept_id=dept.id;
-- 求出‘大数据’部门的最高薪资
select max(sal) from emp where dept_id=30;
-- 列出薪资比 ‘大数据’部门最高薪资还高的员工信息
select emp.name,sal,dept.name from dept right join emp
on emp.dept_id=dept.id
where sal > (select max(sal) from emp where dept_id=30);
多表查询练习
-- 48.列出在'培优部'任职的员工,假定不知道'培优部'的部门编号,显示部门名称,员工名称。
-- 连接查询部门表和员工表
select dept.name,emp.name from dept,emp
where emp.dept_id=dept.id;
-- 求出部门名称为‘培优部’的员工
select dept.name,emp.name from dept,emp
where emp.dept_id=dept.id and dept.name='培优部';
-- 扩展:可以为表名加别名,加了别名后,就需要使用别名替换表名
select d.name,e.name from dept d,emp e
where e.dept_id=d.id and d.name='培优部';
-- 49.(自查询)列出所有员工及其直接上级,显示员工姓名、上级编号,上级姓名
/* 将emp同时看做员工表和上级表
* emp e1 看做员工表 emp e2 看做上级表
* 查询的表: emp e1, emp e2
* 查询的列: e1.name, e2.id, e2.name
* 连接条件: 员工所属上级编号=上级的编号
* e1.topid=e2.id */
select e1.name, e2.id, e2.name
from emp e1, emp e2
where e1.topid=e2.id;
-- 50.列出最低薪资大于1500的各种职位,显示职位和该职位的最低薪资
-- 根据职位进行分组,再求出每个职位的最低薪资
select job, min(sal) from emp group by job;
-- 求出最低薪资大于1500的职位有哪些
select job, min(sal) from emp group by job
having min(sal) > 1500;
补充内容:where和having子句的区别:
(1)相同点: where和having都可以对记录进行筛选过滤。
(2)区别:where是在分组之前,对记录进行筛选过滤,并且where子句中不能使用多行函数以及列别名(但是可以使用表别名)
(3)区别:having是在分组之后,对记录进行筛选过滤,并且having子句中可以使用多行函数以及列别名、表别名。
-- 51.列出在每个部门就职的员工数量、平均工资。显示部门编号、员工数量,平均薪资。
-- 根据部门分组,统计每个组(每个部门)的人数、平均薪资
select dept_id, count(*), avg(sal)
from emp
group by dept_id;
-- 52.查出至少有一个员工的部门,显示部门编号、部门名称、部门位置、部门人数。
-- 连接查询部门表和员工表
select d.id, d.name, d.loc
from dept d, emp e
where d.id=e.dept_id;
-- 根据部门进行分组
select d.id, d.name, d.loc, count(*)
from dept d, emp e
where d.id=e.dept_id
group by d.name
having count(*)>0;
-- 53.列出受雇日期早于直接上级的所有员工,显示员工编号、员工姓名、部门名称。
/* emp e1 员工表, emp e2 上级表
查询的表:emp e1, emp e2, dept d
查询的列:e1.id, e1.name, d.name
连接条件:e1.topid=e2.id
e1.dept_id=d.id
筛选条件:e1.hdate < e2.hdate
*/
select e1.id, e1.name, d.name
from emp e1, emp e2, dept d
where e1.topid=e2.id
and e1.dept_id=d.id
and e1.hdate < e2.hdate;
-- 补充:查询员工表中薪资最高的员工信息
select name, max(sal) from emp; -- 这个查询结果是错误的!
-- 可以按照薪资降序排序,每页显示1条,查询第一页。
select * from emp order by sal desc limit 0,1;
-- 也可以使用子查询
select max(sal) from emp; -- 求emp表中的最高薪资
select * from emp where sal=( select max(sal) from emp );
*****************************************************************************************************************
数据库备份与恢复
备份数据库
在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行备份:
mysqldump -u用户名 -p 数据库的名字 > 备份文件的位置
示例1: 对db40库中的数据(表,表记录)进行备份,备份到 d:/db40.sql文件中
mysqldump -uroot -p db40 > d:/db40.sql
键入密码,如果没有提示,即表示备份成功!
也可以一次性备份所有库,例如:
对mysql服务器中所有的数据库进行备份,备份到 d:/all.sql文件中
mysqldump -uroot -p --all-database > d:/all.sql
键入密码,如果没有提示错误(警告信息不是错误,可以忽略),即表示备份成功!
恢复数据库
在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行恢复:
mysql -u用户名 -p 数据库的名字 < 备份文件的位置
示例:将d:/db40.sql文件中的数据恢复到db60库中
-- 在cmd窗口中(已登录的状态下),先创建db60库:
create database db60 charset utf8;
-- 在cmd窗口中(未登录的状态下)
mysql -uroot -p db60 < d:/db40.sql
2、恢复数据库方式二:
在cmd窗口中(已登录的状态下),可以通过source执行指定位置的SQL文件:
source sql文件的位置
示例:将d:/db40.sql文件中的数据恢复到db80库中
-- 在cmd窗口中(已登录的状态下),先创建db80库,进入db80库:
create database db80 charset utf8;
use db80;
-- 再通过source执行指定位置下的sql文件:
source d:/db40.sql
*****************************************************************************************************************
扩展内容
现创建学生表:
use test; -- 进入test库
drop table if exists stu; -- 删除学生表(如果存在)
create table stu( -- 创建学生表
id int, -- 学生id
name varchar(20), -- 学生姓名
gender char(1), -- 学生性别
birthday date -- 出生年月
);
修改表—新增列
语法:ALTER TABLE tabname ADD col_name datatype DEFAULT expr;
1、往stu表中添加score列,double类型
alter table stu add score double;
修改表—修改列
语法:ALTER TABLE tabname MODIFY (col_name datatype DEFAULT expr...);
1、修改id列,将id设置为主键
alter table stu modify id int primary key;
2、修改id列,将id主键设置为自动增长
alter table stu modify id int auto_increment;
修改表—删除列
语法:ALTER TABLE tabname DROP [COLUMN] col_name;
1、删除stu表中的score列
alter table stu drop score;
添加或删除主键及自增
思考:a) 在建表时,如何为id指定主键约束和自增?
b) 建好的表,如何通过修改添加主键约束和自增?
c) 如何删除表中的主键约束和自增?
1、创建stu学生表,不添加主键自增, 查看表结果
use mydb1; -- 切换到mydb1库
drop table if exists stu; -- 删除stu学生表(如果存在)
create table stu( -- 重建stu学生表,没有主键自增
id int,
name varchar(20),
gender char(1),
birthday date
);
desc stu; -- 查看表结构
表结构如下: 没有主键约束和自增。

2、如果表没有创建,或者要删除重建,在创建时可以指定主键或主键自增
drop table if exists stu; -- 删除stu表
create table stu( -- 重新创建stu表时,指定主键自增
id int primary key auto_increment,
name varchar(20),
gender char(1),
birthday date
);
desc stu; -- 查看表结构
表结构如下: 已经添加了主键约束和自增。

3、如果不想删除重建表,也可以通过修改表添加主键或主键自增
再次执行第1步,创建stu学生表,不添加主键自增,查看表结果
-- 例如: 将stu学生表中的id设置为主键和自动增长
alter table stu modify id int primary key auto_increment;
desc stu; -- 查看表结构

alter table stu modify id int **primary key**;
如果已经添加主键约束,仅仅设置自增,但需注意:
(1)如果没有设置主键,不可添加自增
(2)只有当主键是数值时,才可以添加自增
alter table stu modify id int **auto_increment**;
4、如果想删除主键自增
-- 删除主键自增时,要先删除自增
alter table stu modify id int;
-- 再删除主键约束
alter table stu drop primary key;
desc stu; -- 查看表结构

添加外键约束
1、添加外键方式一:建表时添加外键
现有部门表如下:
-- 创建部门表
create table dept(
id int primary key auto_increment, -- 部门编号
name varchar(20) -- 部门名称
);
要求创建员工表,并在员工表中添加外键关联部门主键
-- 创建员工表
create table emp(
id int primary key auto_increment, -- 员工编号
name varchar(20), -- 员工姓名
dept_id int, -- 部门编号
foreign key(dept_id) references dept(id) -- 指定dept_id为外键
);
2、添加外键方式二:建表后添加外键
现有部门表和员工表:
-- 创建部门表
create table dept(
id int primary key auto_increment, -- 部门编号
name varchar(20) -- 部门名称
);
-- 创建员工表
create table emp(
id int primary key auto_increment, -- 员工编号
name varchar(20), -- 员工姓名
dept_id int -- 部门编号
);
-- 如果表已存在,可以使用下面这种方式:
alter table emp add constraint fk_dept_id foreign key(dept_id) references dept(id);
其中 fk_dept_id (名字由自己定义),是指外键约束名称,也可以将【constraint fk_dept_id】省略,MySQL会自动分配一个外键名称,将来可以通过该名称删除外键。
foreign key(dept_id)中的dept_id为外键
删除外键约束
1、首先通过 “show create table 表名”语法,查询含有外键表的建表语句,例如:
show create table emp;
显示结果如下:

添加外键约束(多对多)
-- 现有学生(stu)表和教师(tea)表:
-- 创建学生表
create table stu(
stu_id int primary key auto_increment, -- 学生编号
name varchar(20) -- 学生姓名
);
-- 创建教师表
create table tea(
tea_id int primary key auto_increment, -- 教师编号
name varchar(20) -- 教师姓名
);
-- 添加第三方表(stu_tea)表示学生表和教师表关系
-- 创建学生和教师关系表
create table stu_tea(
stu_id int, -- 学生编号
tea_id int, -- 教师编号
primary key(stu_id,tea_id), -- 设置联合主键
foreign key(stu_id) references stu(stu_id), -- 添加外键
foreign key(tea_id) references tea(tea_id) -- 添加外键
);
其中为了防止重复数据,将stu_id和tea_id设置为联合主键。
将stu_id设置为外键,参考stu表中的stu_id列
并将tea_id设置为外键,参考tea表中的tea_id列
级联更新、级联删除
-- 创建db20库、dept表、emp表并插入记录
-- 删除db20库(如果存在),并重新创建db20库
drop database if exists db20;
create database db20 charset utf8;
use db20;
-- 创建部门表, 要求id, name字段
create table dept(
id int primary key auto_increment, -- 部门编号
name varchar(20) -- 部门名称
);
-- 往部门表中插入记录
insert into dept values(null, '财务部');
insert into dept values(null, '人事部');
insert into dept values(null, '科技部');
insert into dept values(null, '销售部');
-- 创建员工表, 要求id, name, dept_id
create table emp(
id int primary key auto_increment, -- 员工编号
name varchar(20), -- 员工姓名
dept_id int, -- 部门编号
foreign key(dept_id) references dept(id) -- 指定外键
on update cascade -- 级联更新
on delete cascade -- 级联删除
);
insert into emp values(null, '张三', 1);
insert into emp values(null, '李四', 2);
insert into emp values(null, '老王', 3);
insert into emp values(null, '赵六', 4);
insert into emp values(null, '刘能', 4);
级联更新:主表(dept表)中的主键发生更新时(例如将销售部的id改为40),从表(emp表)中的记录的外键数据也会跟着该表(即赵六和刘能的部门编号也会更新为40)
级联删除:如果不添加级联删除,当删除部门表中的某一个部门时(例如删除4号部门),若该部门在员工表中有对应的员工(赵六和刘能),删除会失败!
若果添加了级联删除,当删除部门表中的某一个部门时,若该部门在员工表中有对应的员工,会在删除部门的同时,将员工表中对应的员工也删除!
where中不能使用列别名
SQL语句的书写顺序:
select * | 列名 -- 确定要查询的列有哪些
from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount -- 指定返回第几页记录以及每页显示多少条
SQL语句的执行顺序:
from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
select * | 列名 列别名 -- 确定要查询的列有哪些,
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount
关于where中不能使用列别名但是可以使用表别名?**
是因为,表别名是声明在from中,from先于where执行,先声明再使用没有问题,但是列别名是声明在select中,where先于select执行,如果先使用列别名,再声明,这样执行会报错!!

浙公网安备 33010602011771号