Mysql基础(三)多表查询

学习之前需要创建的数据表和数据

copy
-- 部门表 CREATE TABLE `dept` ( `depton` mediumint(8) UNSIGNED NOT NULL DEFAULT 0, `dname` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `loc` varchar(13) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK'); INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS'); INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO'); INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON'); select * from dept -- 员工表 CREATE TABLE `emp` ( `empon` mediumint(8) UNSIGNED NOT NULL DEFAULT 0, `ename` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `job` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `mgr` mediumint(8) UNSIGNED NULL DEFAULT NULL, `hiredate` date NOT NULL, `sal` decimal(7, 2) NOT NULL, `comm` decimal(7, 2) NULL DEFAULT NULL, `depton` mediumint(8) UNSIGNED NOT NULL DEFAULT 0 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1990-12-17', 800.00, NULL, 20); INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1991-02-20', 1600.00, 300.00, 30); INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7968, '1991-02-22', 1250.00, 500.00, 30); INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1991-04-02', 2975.00, NULL, 20); INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7968, '1991-09-28', 1250.00, 1400.00, 30); INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1991-05-01', 2850.00, NULL, 30); INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1991-06-09', 2450.00, NULL, 10); INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1991-04-19', 3000.00, NULL, 20); INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1991-11-17', 5000.00, NULL, 10); INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1991-09-08', 1500.00, NULL, 30); INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '1991-12-03', 950.00, NULL, 30); INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1991-12-03', 3000.00, NULL, 20); INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1991-01-23', 1300.00, NULL, 10); select * from emp -- 薪水等级表 CREATE TABLE `salgrade` ( `grade` mediumint(8) UNSIGNED NOT NULL DEFAULT 0, `losal` decimal(17, 2) NOT NULL, `hisal` decimal(17, 2) NOT NULL ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `salgrade` VALUES (1, 700.00, 1200.00); INSERT INTO `salgrade` VALUES (2, 1201.00, 1400.00); INSERT INTO `salgrade` VALUES (3, 1401.00, 2000.00); INSERT INTO `salgrade` VALUES (4, 2001.00, 3000.00); INSERT INTO `salgrade` VALUES (5, 3001.00, 9999.00); select * from salgrade

一、查询加强

1、条件查询

  • 使用where子句

    如何查询1992.1.1后入职的员工

    在mysql中,日期类型可以直接比较

    copy
    select * from emp where hiredate <= '1992-01-01'
  • 使用like操作符
    %:表示0到多个字符,_(下划线):表示单个任意字符
    如何显示首字符为 S 的员工姓名和工资

    copy
    select ename,sal from emp where ename like 'S%'

    如何显示第三个字符为大写 O 的所有员工名字和工资

    copy
    select ename,sal from emp where ename like '__O%'
  • 如何显示没有伤及的雇员情况

    copy
    select * from emp where mgr is null
  • 查询表结构

    copy
    desc emp
  • 使用order by子句

    如何按照工资的从高到低顺序,显示雇员信息

    copy
    -- 从低到高 select * from emp order by sal asc -- 从高到低 select * from emp order by sal desc

    按照部门号升序而雇员的工资降序排列,显示雇员信息

    copy
    select * from emp order by depton asc,sal desc

2、分页查询

基本语法:

copy
select .... limit start,rows

表示从 start+1 行开始取,取出rows行,start 从0开始计算

练习:按雇员的id号降序取出,每页显示5条记录。请分别显示第3页,第5页对应的sql语句

copy
-- 第一页 select * from emp order by empon desc limit 0,5 -- 第二页 select * from emp order by empon desc limit 5,5 -- 第三页 select * from emp order by empon desc limit 20,5

推导公式:

copy
-- 推到分页公式 select * from emp order by empon asc limit (rows*start-1),rows

3、分组加强

使用分组函数和分组子句 group by

练习代码:

copy
-- 显示每种岗位的雇员总数,平均工资 select count(*),avg(sal),job from emp group by job -- 显示雇员总数,以及获得补助的雇员数 select count(*),count(comm) from emp -- 统计没有获得补助的雇员数 -- count() 函数会过滤掉为null的数据,不进行统计 -- if(comm is null,1,null) 如果这个字段为null,返回一个null,不为null,返回 1 select count(*),count(if(comm is null,1,null)) from emp -- 显示管理者的总人数 -- distinct 去重 select count(distinct mgr) from emp -- 显示雇员工资的最大差额 select max(sal) - min(sal) from emp

4、多子句查询

子句顺序:

copy
select column1,column2,.....from table_name group by column having condition order by column limit start,rows

练习:

copy
-- 统计各个部门的平均工资,并且是大于1000的,并且按照平均工资从高到底排序,取出前2条记录 select depton,avg(sal) avg_sal from emp group by depton having avg_sal > 1000 order by avg_sal desc limit 0,2

二、多表查询

说明:多表查询指的是基于两个和两个以上的表查询,在实际应用中,查询单个表可能不能满足你的需求

1、多表笛卡尔集

在没有加上限定条件下出现的问题:

copy
select * from emp,dept

在默认情况下,当两个表查询时,规则

1、从第二张表中,取出一行和第二张表的每一行进行组合,返回的结果含有两张表的所有列

2、一共返回的记录数:第一张表的行数 x 第二张表的行数

3、这样多表查询默认处理返回的结果,称为笛卡尔集

4、解决这种多表的关键就是要写出正确的过滤条件 where,需要程序员进行分析

解决问题示例代码:

copy
select ename,sal,dname,dept.depton from emp,dept where emp.depton = dept.depton

注意事项:

多表查询的条件不能少于 表的个数-1,否则会出现笛卡尔集

多表查询练习:

copy
-- 显示各个员工的姓名,工资以及其工资的级别 select ename,sal,grade from emp,salgrade where sal between losal and hisal -- 显示雇员名,雇员工资所在部门的名字,并按部门排序【降序】 select ename,sal,dname from emp,dept where dept.depton = emp.depton order by sal desc

2、自连接

说明:自连接是指在同一张表的连接查询【将同一张表看做两张表】

分析:

1、员工名字在emp表,上级的名字在 emp表

2、员工和上级通过emp表的mgr列关联

3、自连接使用别名进行区分表

copy
select worker.ename '员工名',boss.ename '上级名' from emp worker,emp boss where worker.mgr = boss.empon

特点:

1、把同一张表看做两张表进行使用

2、需要给表取别名,表名 表别名

3、列名不明确,可指定列的别名

3、子查询

说明:子查询是指嵌入在其他sql语句总的select语句,也叫嵌套查询

  • 单行子查询

    单行子查询是指返回一行数据的子查询语句

  • 多行子查询

    多行子查询指返回多行数据的子查询,使用关键字in

练习:

copy
-- 查询和部门编号为10的工作相同的雇员 -- 的名字、岗位、工资、部门号,但是不包含自己的 -- 1、先查询10号部门的岗位,去重 select distinct job from emp where depton = 10 -- 2、把上面查询的结果当做子查询使用 select ename,job,sal,depton from emp where job in ( select distinct job from emp where depton = 10 ) and depton != 10 -- 查询每个部门最高工资的人员工的名字和部门名称 select emp.ename,temp.max_sal,dname from ( select max(sal) max_sal,depton from emp group by depton ) temp,emp,dept where temp.max_sal = emp.sal and temp.depton = dept.depton order by emp.depton

all 和 any 的使用

all 的使用

all 的意思就是:查询的员工工资,必须要比所有30部门的员工工资高可以

copy
-- 显示工资比部门30的所有员工的工资高的员工姓名、工资和部门号 -- 第一种方式 select ename,sal,depton from emp where sal > all( select sal from emp where depton = 30 ) -- 第二种方式 select ename,sal,depton from emp where sal > ( select max(sal) from emp where depton = 30 )

any 的使用

any 的意思是,查询的员工工资,只要有一个员工工资比30号部门工资高就可以

copy
-- 显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号 -- 第一种方式 select ename,sal,depton from emp where sal > any( select sal from emp where depton = 30 ) -- 第二种方式 select ename,sal,depton from emp where sal > ( select min(sal) from emp where depton = 30 )

多列子查询

多列子查询是指查询返回多个列数据的子查询语句

copy
-- 查询与allen的部门和岗位完全相同的所有雇员(不包含allen本人) select * from emp where (depton,job) = ( select depton,job from emp where ename = 'allen' ) and ename != 'allen'

子查询练习题

copy
-- 查询每个部门工资高于本部门平均工资的人的资料 -- 先查询每个部门的平均工资 select avg(sal) avg_sal,depton from emp group by depton select ename,sal,t.avg_sal,t.depton from emp e,(select avg(sal) avg_sal,depton from emp group by depton) t where e.sal > t.avg_sal and e.depton = t.depton -- 查找每个部门工资最高的人的详细资料 -- 先查找每个部门的最高工资 select max(sal) max_sal,depton from emp group by depton select * from emp e,(select max(sal) max_sal,depton from emp group by depton) t where e.sal = t.max_sal and e.depton = t.depton -- 查询每个部门的信息(部门编号,名称,地址)和人员数量 -- 先统计每个部门的人数 select count(depton) count_num,depton from emp group by depton -- 在多表查询中,当多个表的列名不重复时,才可以直接写列名 select d.*,t.count_num from dept d,( select count(depton) count_num,depton from emp group by depton )t where d.depton = t.depton

三、表复制和去重

1、自我复制数据(蠕虫复制)

使用场景:有时,为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据

(1)首先创建一张表

copy
-- 包含emp的一些字段 create table my_tab01( id int, `name` varchar(32), sal double, job varchar(32), depton int )

(2)将emp表的数据复制 my_tab01

copy
insert into my_tab01 (id,`name`,sal,job,depton) select empon,ename,sal,job,depton from emp

(3)自我复制

copy
insert into my_tab01 select * from my_tab01

2、表的去重

如何去掉表中重复的数据

(1)创建一张表,结构与emp一致

copy
-- 把emp表的结构复制到my_tab02 create table my_tab02 like emp

(2)将emp表的数据插入my_tab02表中

copy
insert into my_tab02 select * from emp

(3)去重 my_tab02 的记录

思路:

(1)先创建一张临时表 my_tmp,该表的结构 和 my_tab02 一样

copy
create table my_tmp like my_tab02

(2)把 my_tmp 的记录通过 distinct 关键字处理后,把记录复制到 my_tmp

copy
insert into my_tmp select distinct * from my_tab02

(3)清除掉 my_tab02 的记录

copy
delete from my_tab02

(4)把 my_tmp 表的记录复制到 my_tab02

copy
insert into my_tab02 select * from my_tmp

(6)删除 my_tmp 表

copy
drop table my_tmp

四、合并查询

说明:有时在实际应用中,为了合并多个select语句的结果,可以使用集合操作符号 union,union all

1、union all

该操作符用于取得两个结果集的并集,当使用该操作符时,不会取消重复行

copy
select ename,sal,job from emp where sal > 2500 union all select ename,sal,job from emp where job = 'MANAGER'

2、union

该操作符用于取得两个结果集的并集,当使用该操作符时,会取消重复行

copy
select ename,sal,job from emp where sal > 2500 union select ename,sal,job from emp where job = 'MANAGER'

五、外连接

只要的连接方式

1、左外连接

(左侧的表数据完全显示称为左外连接)

即使左边的表跟右边的表没有匹配的记录,那么左边的表数据也会完全显示出来

基本语法:

copy
select cloumn1,cloumn2,cloumn3 from table_name01 left join table_name02 on 条件

2、右外连接

(右侧的表数据完全显示称为右外连接)

即使右边的表跟左边的表没有匹配的记录,那么右边的表数据也会完全显示出来

基本语法:

copy
select cloumn1,cloumn2,cloumn3 from table_name01 right join table_name02 on 条件

3、内连接

(只返回两个表的结果集的交集)

也就是说,当左边表的数据与右边表的数据没有匹配的记录,那么就把左边表没有匹配的记录过滤掉,只显示与右边表匹配的记录

copy
select cloumn1,cloumn2,cloumn3 from table_name01 inner join table_name02 on 条件

测试代码:

copy
create table stu( id int, `name` varchar(21) ) insert into stu values(1,'Jack'),(2,'Tom'),(3,'Kity'),(4,'nono') create table exam( id int, grade int ) insert into exam values(1,56),(2,76),(11,8) -- 使用左外连接(显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩为空) select s.id,s.`name`,e.grade from stu s left join exam e on s.id = e.id -- 使用右外连接(显示所有成绩,如果没有名字,显示为空) select s.id,s.`name`,e.grade from stu s right join exam e on s.id = e.id -- 内连接 select s.id,s.`name`,e.grade from stu s inner join exam e on s.id = e.id
posted @   花椒蛋炒饭  阅读(129)  评论(0编辑  收藏  举报
相关博文:
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起