mysql四-2:多表查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql四-2:多表查询相关的知识,希望对你有一定的参考价值。

一、准备表

新建表

mysql> create table department(

    id int,

    name varchar(20) 

    );

mysql> create table employee(

    id int primary key auto_increment,

    name varchar(20),

    sex enum('male','female') not null default 'male',

    age int,

    dep_id int

    );

插入数据

mysql> insert into department values

    (200,'技术'),

    (201,'人力资源'),

    (202,'销售'),

    (203,'运营');

mysql> insert into employee(name,sex,age,dep_id) values

    ('egon','male',18,200),

    ('alex','female',48,201),

    ('wupeiqi','male',38,201),

    ('yuanhao','female',28,202),

    ('liwenzhou','male',18,200),

    ('jingliyang','female',18,204)

    ;

查看表结构和数据

mysql> desc department;

mysql> desc employee;

mysql> select * from department;

mysql> select * from employee;


二、多表连接查询

重点!!!外链接语法

    ELECT 字段列表 FROM 表1 INNER|LEFT|RIGHT JOIN 表2 ON 表1.字段 = 表2.字段;

1、交叉连接:不适用任何匹配条件。生成笛卡尔积

mysql> select * from employee,department;

2、内连接:只连接匹配的行

找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果

    select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; 

上述sql等同于

    select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;

注意:department没有204这个部门,因而employee表中关于204这条员工信息没有匹配出来

3、外链接之左连接:优先显示左表全部记录

以左表为准,即找出所有员工信息,当然包括没有部门的员工;本质就是:在内连接的基础上增加左边有右边没有的结果

    select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id;

4、外链接之右连接:优先显示右表全部记录

以右表为准,即找出所有部门信息,包括没有员工的部门;本质就是:在内连接的基础上增加右边有左边没有的结果

    select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;

5、全外连接:显示左右两个表全部记录

在内连接的基础上增加左边有右边没有的和右边有左边没有的结果

注意:mysql不支持全外连接 full JOIN

强调:mysql可以使用此种方式间接实现全外连接

    select * from employee left join department on employee.dep_id = department.id union select * from employee right join department on employee.dep_id = department.id;

注意 union与union all的区别:union会去掉相同的纪录


三、符合条件连接查询

示例1:以内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门

    select employee.name,department.name from employee inner join department on employee.dep_id = department.id where age > 25;

示例2:以内连接的方式查询employee和department表,并且以age字段的升序方式显示

    select employee.id,employee.name,employee.age,department.name from employee,department where employee.dep_id = department.id and age > 25 order by age asc;


四 子查询

    1)子查询是将一个查询语句嵌套在另一个查询语句中。

    2)内层查询语句的查询结果,可以为外层查询语句提供查询条件。

    3)子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字

    4)还可以包含比较运算符:= 、 !=、> 、<等

1、带IN关键字的子查询

查询平均年龄在25岁以上的部门名

    select id,name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25);

查看技术部员工姓名

    select name from employee where dep_id in (select id from department where name='技术');

查看不足1人的部门名(子查询得到的是有人的部门id)

    select name from department where id not in (select distinct dep_id from employee);

2、带比较运算符的子查询

比较运算符:=、!=、>、>=、<、<=、<>

查询大于所有人平均年龄的员工名与年龄

    select name,age from emp where age > (select avg(age) from emp);

查询大于部门内平均年龄的员工名、年龄

    select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age; 

3、带EXISTS关键字的子查询

EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。而是返回一个真假值。True或False,当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询

department表中存在dept_id=203,Ture

    select * from employee where exists (select id from department where id=200);

department表中存在dept_id=205,False

    select * from employee where exists (select id from department where id=204);

4、练习:查询每个部门最新入职的那位员工

准备表:

mysql>create table employee(

    id int not null unique auto_increment,

    name varchar(20) not null,

    sex enum('male','female') not null default 'male', #大部分是男的

    age int(3) unsigned not null default 28,

    hire_date date not null,

    post varchar(50),

    post_comment varchar(100),

    salary double(15,2),

    office int, #一个部门一个屋子

    depart_id int

    );

mysql>insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values

    ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部

    ('alex','male',78,'20150302','teacher',1000000.31,401,1),

    ('wupeiqi','male',81,'20130305','teacher',8300,401,1),

    ('yuanhao','male',73,'20140701','teacher',3500,401,1),

    ('liwenzhou','male',28,'20121101','teacher',2100,401,1),

    ('jingliyang','female',18,'20110211','teacher',9000,401,1),

    ('jinxin','male',18,'19000301','teacher',30000,401,1),

    ('成龙','male',48,'20101111','teacher',10000,401,1),

    ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门

    ('丫丫','female',38,'20101101','sale',2000.35,402,2),

    ('丁丁','female',18,'20110312','sale',1000.37,402,2),

    ('星星','female',18,'20160513','sale',3000.29,402,2),

    ('格格','female',28,'20170127','sale',4000.33,402,2),

    ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门

    ('程咬金','male',18,'19970312','operation',20000,403,3),

    ('程咬银','female',18,'20130311','operation',19000,403,3),

    ('程咬铜','male',18,'20150411','operation',18000,403,3),

    ('程咬铁','female',18,'20140512','operation',17000,403,3)

    ;

答案1:链表

    SELECT * FROM employee AS t1 INNER JOIN (

        SELECT post,max(hire_date) max_date FROM employee GROUP BY post ) AS t2 ON t1.post = t2.post

    WHERE t1.hire_date = t2.max_date;

答案2:子查询

    select t3.name,t3.post,t3.hire_date from employee as t3 where id in (select (select id from employee as t2 where t2.post=t1.post order by hire_date desc limit 1) from employee as t1 group by post);


五、综合练习

1、准备表、记录

mysql> create database db1;

mysql> use db1;

mysql> source /root/init.sql (从init.sql文件中导入数据)

2、题目

1)查询所有的课程的名称以及对应的任课老师姓名

    select 

        teacher.tname,

        course.cname 

    from 

        teacher 

        inner join course on teacher.tid = course.teacher_id;

2)查询学生表中男女生各有多少人

    select gender,count(sid) from student group by gender;

3)查询物理成绩等于100的学生的姓名

    select 

        student.sname 

    from 

        student 

    where 

        sid in (

            select 

                student_id 

            from 

                score 

            inner join course on score.course_id = course.cid 

            WHERE 

                course.cname = '物理' AND score.num = 100);

4)查询平均成绩大于八十分的同学的姓名和平均成绩

    select 

        student.sname,

        t1.avg_num 

    from 

        student 

    inner join (

        select 

            student_id

            avg(num) AS avg_num 

        from 

            score 

        group by 

            student_id 

        having 

            avg(num) > 80

        )AS t1 on student.sid=t1.student_id;

5)查询所有学生的学号,姓名,选课数,总成绩

    SELECT

        student.sid,

        student.sname,

        t1.course_num,

        t1.total_num

    FROM

        student

    LEFT JOIN (

        SELECT

            student_id,

            COUNT(course_id) course_num,

            sum(num) total_num

        FROM

            score

        GROUP BY

            student_id

    ) AS t1 ON student.sid = t1.student_id;

6)查询姓李老师的个数

    select count(tid) from teacher where tname LIKE '李%';

7)查询没有报李平老师课的学生姓名

    select 

        student.sname

    from 

        student 


8)查询物理课程比生物课程高的学生的学号


9)查询没有同时选修物理课程和体育课程的学生姓名


10)查询挂科超过两门(包括两门)的学生姓名和班级


11)查询选修了所有课程的学生姓名


12)查询李平老师教的课程的所有成绩记录

 

13)查询全部学生都选修了的课程号和课程名


14)查询每门课程被选修的次数


15)查询之选修了一门课程的学生姓名和学号


16)查询所有学生考出的成绩并按从高到低排序(成绩去重)


17)查询平均成绩大于85的学生姓名和平均成绩


18)查询生物成绩不及格的学生姓名和对应生物分数


19)查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名


20)查询每门课程成绩最好的前两名学生姓名


21)查询不同课程但成绩相同的学号,课程号,成绩


22)查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;


23)查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;


24)任课最多的老师中学生单科成绩最高的学生姓名


以上是关于mysql四-2:多表查询的主要内容,如果未能解决你的问题,请参考以下文章

mysql四-2:多表查询

MySQL多表查询

MySQL 多表查询(Day43)

134 MySQL多表查询

MySQL多表查询一网打尽

Mysql-多表连接的操作和用法