[MySQL | Basics] 04. MySQL multi-table query

Table of contents

1. Multi-table relationship

1.1 One-to-many

​1.2 Many-to-many

1.3 One to one

2. Overview of multi-table query

2.1 Data preparation

2.2 Overview

2.3 Classification

3. Inner connection 

3.1 Case

4. Outer connection 

4.1 Case

5. Self-connection

5.1 Self-join query

5.2 Joint query

6. Sub query

6.1 Overview

6.2 Scalar Subqueries

6.3 Column query

6.4 Row Subqueries

6.5 Table subqueries

Seven, multi-table query case practice


1. Multi-table relationship

        During project development, when designing the database table structure, the table structure will be analyzed and designed according to the business requirements and the relationship between the business modules. Since the businesses are interrelated, there are various connections between the table structures. There are basically three types:

  • One-to-many (many-to-one)
  • many to many
  • one to one

1.1 One-to-many

  • Case: the relationship between departments and employees

  • Relationship: One department corresponds to multiple employees, and one employee corresponds to one department

  • Realization: Create a foreign key on the many side, pointing to the primary key on the one side

1.2 Many-to-many

  • Case: Student-Course Relationship

  • Relationship: A student can choose multiple courses, and a course can also be chosen by multiple students

  • Implementation: Create a third intermediate table, the intermediate table contains at least two foreign keys, which are associated with the primary keys of the two parties 

Corresponding SQL script:

create table student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
) comment '学生表';
insert into student values (null, '黛绮丝', '2000100101'),(null, '谢逊', '2000100102'),(null, '殷天正', '2000100103'),(null, '韦一笑', '2000100104');


create table course(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '课程名称'
) comment '课程表';
insert into course values (null, 'Java'), (null, 'PHP'), (null , 'MySQL') , (null, 'Hadoop');


create table student_course(
    id int auto_increment comment '主键' primary key,
    studentid int not null comment '学生ID',
    courseid  int not null comment '课程ID',
    constraint fk_courseid foreign key (courseid) references course (id),
    constraint fk_studentid foreign key (studentid) references student (id)
)comment '学生课程中间表';

insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,2),(null,2,3),(null,3,4);

1.3 One to one

  • Case: Relationship between users and user details

  • Relationship: One-to-one relationship, mostly used for single-table splitting, put the basic fields of one table in one table, and put other detailed fields in another table to improve operational efficiency

  • Implementation: Add a foreign key to either side, associate the primary key of the other side, and set the foreign key to be unique (UNIQUE)

Corresponding SQL script: 

create table tb_user(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    age int comment '年龄',
    gender char(1) comment '1: 男 , 2: 女',
    phone char(11) comment '手机号'
) comment '用户基本信息表';

create table tb_user_edu(
    id int auto_increment primary key comment '主键ID',
    degree varchar(20) comment '学历',
    major varchar(50) comment '专业',
    primaryschool varchar(50) comment '小学',
    middleschool varchar(50) comment '中学',
    university varchar(50) comment '大学',
    userid int unique comment '用户ID',
    constraint fk_userid foreign key (userid) references tb_user(id)
) comment '用户教育信息表';


insert into tb_user(id, name, age, gender, phone) values
        (null,'黄渤',45,'1','18800001111'),
        (null,'冰冰',35,'2','18800002222'),
        (null,'码云',55,'1','18800008888'),
        (null,'李彦宏',50,'1','18800009999');

insert into tb_user_edu(id, degree, major, primaryschool, middleschool, university, userid) values
        (null,'本科','舞蹈','静安区第一小学','静安区第一中学','北京舞蹈学院',1),
        (null,'硕士','表演','朝阳区第一小学','朝阳区第一中学','北京电影学院',2),
        (null,'本科','英语','杭州市第一小学','杭州市第一中学','杭州师范大学',3),
        (null,'本科','应用数学','阳泉第一小学','阳泉区第一中学','清华大学',4);

2. Overview of multi-table query

2.1 Data preparation

1). Delete the test data of the previous emp, dept table

2). Execute the following script to create emp table and dept table and insert test data

-- 创建 dept 表,并插入数据
create table dept(
    id   int auto_increment comment 'ID' primary key,
    name varchar(50) not null comment '部门名称'
)comment '部门表';

-- 创建 emp 表,并插入数据
create table emp(
    id  int auto_increment comment 'ID' primary key,
    name varchar(50) not null comment '姓名',
    age  int comment '年龄',
    job varchar(20) comment '职位',
    salary int comment '薪资',
    entrydate date comment '入职时间',
    managerid int comment '直属领导ID',
    dept_id int comment '部门ID'
)comment '员工表';

-- 添加外键
alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id);

INSERT INTO dept (id, name) VALUES (1, '研发部'), (2, '市场部'),(3, '财务部'), (4, '销售部'), (5, '总经办'), (6, '人事部');
INSERT INTO emp (id, name, age, job,salary, entrydate, managerid, dept_id) VALUES
            (1, '金庸', 66, '总裁',20000, '2000-01-01', null,5),

            (2, '张无忌', 20, '项目经理',12500, '2005-12-05', 1,1),
            (3, '杨逍', 33, '开发', 8400,'2000-11-03', 2,1),
            (4, '韦一笑', 48, '开发',11000, '2002-02-05', 2,1),
            (5, '常遇春', 43, '开发',10500, '2004-09-07', 3,1),
            (6, '小昭', 19, '程序员鼓励师',6600, '2004-10-12', 2,1),

            (7, '灭绝', 60, '财务总监',8500, '2002-09-12', 1,3),
            (8, '周芷若', 19, '会计',48000, '2006-06-02', 7,3),
            (9, '丁敏君', 23, '出纳',5250, '2009-05-13', 7,3),

            (10, '赵敏', 20, '市场部总监',12500, '2004-10-12', 1,2),
            (11, '鹿杖客', 56, '职员',3750, '2006-10-03', 10,2),
            (12, '鹤笔翁', 19, '职员',3750, '2007-05-09', 10,2),
            (13, '方东白', 19, '职员',5500, '2009-02-12', 10,2),

            (14, '张三丰', 88, '销售总监',14000, '2004-10-12', 1,4),
            (15, '俞莲舟', 38, '销售',4600, '2004-10-12', 14,4),
            (16, '宋远桥', 40, '销售',4600, '2004-10-12', 14,4),
            (17, '陈友谅', 42, null,2000, '2011-10-12', 1,null);

2.2 Overview

Multi-table query refers to querying data from multiple tables.

Originally, to query single-table data, the executed SQL form is: select * from emp;

Then if we want to perform multi-table query, we only need to use commas to separate multiple tables, such as: select * from emp , dept ; the specific execution results are as follows:

        At this point, we see that the query results contain a large number of result sets, a total of 102 records, which are actually all combinations of all records (17) in the employee table emp and all records in the department table dept (6). The phenomenon is called the Cartesian product. Next, let’s briefly introduce the Cartesian product.

Cartesian product: Cartesian product refers to all combinations of two sets A and B in mathematics. 

In multi-table queries, we need to eliminate invalid Cartesian products, and only keep the data in the associated part of the two tables. 

In the SQL statement, how to remove the invalid Cartesian product? We can add conditions for join queries to multi-table queries. 

-- 多表查询 -- 笛卡尔积
select * from emp , dept where emp.dept_id = dept.id;

        However, since the employee with id 17 has no dept_id field value, it is not queried according to the conditions of the connection query during multi-table query. 

2.3 Classification

Connection query:

  • Inner join: equivalent to querying the intersection data of A and B

  • Outer join:

  • Left outer join: Query all data in the left table, and some data in the intersection of two tables

  • Right outer join: Query all data in the right table, and some data in the intersection of two tables

  • Self-join: the connection query between the current table and itself, the self-join must use the table alias

subquery:

3. Inner connection 

The inner join query is the data in the intersection of two tables. (that is, the data in the green part)

There are two syntaxes for inner joins: implicit inner joins and explicit inner joins. Let's learn the specific grammatical structure first.

1). Implicit inner join

SELECT 字段列表 FROM 表1 , 表2 WHERE 条件 ... ;

2). Explicit inner join

SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ... ;

3.1 Case

A. Query the name of each employee, and the name of the associated department (implicit inner connection implementation)

     Table structure: emp, dept

     Join condition: 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. Query the name of each employee, and the name of the associated department (explicit inner connection implementation) --- INNER JOIN ... ON ...

     Table structure: emp, dept

     Join condition: 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;

Table alias: ①. tablea as alias 1, tableb as alias 2; ②. tablea alias 1, tableb alias 2;

Note: Once an alias is created for the table, you can no longer use the table name to specify the corresponding field. At this time, you can only use the alias to specify the field.

4. Outer connection 

There are two types of outer joins: left outer join and right outer join. The specific grammatical structure is:

1). Left outer join

SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;

The left outer join is equivalent to querying all the data in table 1 (left table), and of course also includes the data in the intersection of table 1 and table 2.

2). Right outer join

SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;

The right outer join is equivalent to querying all the data in table 2 (right table), and of course also includes the data in the intersection of table 1 and table 2.

4.1 Case

A. Query all the data in the emp table, and the corresponding department information (left outer join)
     table structure: emp, dept
     join condition: 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. Query all the data in the dept table, and the corresponding employee information (right outer join)
     table structure: emp, dept
     join condition: 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;

5. Self-connection

5.1 Self-join query

        Self-join query, as the name suggests, is to connect itself, that is, to connect a table to query multiple times. Let's first learn the query syntax of self-join:

SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;

For a self-join query, it can be an inner join query or an outer join query.

the case

A. Query the names of employees and their leaders

     Table structure: emp

select a.name , b.name from emp a , emp b where a.managerid = b.id;

B. Query the name emp of all employees emp and their leaders. If the employee has no leader, it also needs to be queried

     Table structure: emp a , emp b

select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid = b.id;

Precautions:

        In the self-join query, it is necessary to alias the table, otherwise we do not know the specified conditions, the returned fields, and which table field it is.

5.2 Joint query

For union query, the results of multiple queries are combined to form a new query result set. 

SELECT 字段列表 FROM 表A ...
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....;
  • For the joint query, the number of columns and field types of multiple tables must be consistent.

  • union all will directly merge all the data together, and union will deduplicate the merged data.

case:

A. Query all employees whose salary is less than 5000 and employees whose age is greater than 50.

        Currently, for this requirement, we can directly use multi-condition query, and use the logical operator or to connect. Here, we can also combine queries through union/union all.

select * from emp where salary < 5000
union all
select * from emp where age > 50;

The results of the union all query are simply merged without deduplication. 

select * from emp where salary < 5000
union
select * from emp where age > 50;

The union joint query will deduplicate the query results.

        Note: If the number of fields in the query results of multiple query statements is inconsistent, an error will be reported when performing a union/union all joint query.

6. Sub query

6.1 Overview

1). Concept

Nested SELECT statements in SQL statements are called nested queries, also known as subqueries. 

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

The statement outside the subquery can be any one of INSERT / UPDATE / DELETE / SELECT.

2). Classification

According to different subquery results, it is divided into:

  • Scalar subquery (subquery result is a single value)

  • Column subquery (the result of the subquery is a column)

  • Row subquery (the result of the subquery is one row)

  • Table subquery (the result of the subquery is multiple rows and multiple columns)

According to the position of the subquery, it is divided into:

  • after WHERE

  • after FROM

  • after SELECT 

6.2 Scalar Subqueries

        A subquery returns a single value (number, string, date, etc.), and in its simplest form, such a subquery is called a scalar subquery.

Commonly used operators: = <> > >= < <=

A. Query all employee information of "Sales Department"

When completing this requirement, we can decompose the requirement into two steps:

①. Query the department ID of "Sales Department"

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

②. Query employee information according to the department ID of "Sales Department"

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

B. Query employee information after "Fang Dongbai" joins the job

When completing this requirement, we can decompose the requirement into two steps:

①. Query Fang Dongbai's entry date 

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

②. Query the information of employees who joined after the specified (Oriental White) entry date

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

6.3 Column query

The result returned by a subquery is a column (can be multiple rows), this subquery is called a column subquery.

Commonly used operators: IN , NOT IN , ANY , SOME , ALL

case:

A. Query all employee information of "Sales Department" and "Marketing Department"

Break down into the following two steps:

①. Query the department IDs of "Sales Department" and "Marketing Department" 

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

②. Query employee information according to the department ID

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

B. Query information about employees whose salary is higher than that of everyone in the finance department

Break down into the following two steps:

①. Query the salary of all financial department personnel

select id from dept where name = '财务部';

select salary from emp where dept_id = (select id from dept where name = '财务部');

②. Employee information whose salary is higher than that of everyone in the finance department

select * from emp where salary > all ( select salary from emp where dept_id = (select id from dept where name = '财务部') );

C. Query information about employees whose salary is higher than that of one of the employees in the R&D department

Break down into the following two steps:

①. Query the salary of the owner of the R&D department

select salary from emp where dept_id = (select id from dept where name = '研发部');

②. Information about employees whose salary is higher than that of the lowest one in the R&D department

select * from emp where salary > some ( select salary from emp where dept_id = (select id from dept where name = '研发部') );

6.4 Row Subqueries

The result returned by a subquery is a row (can be multiple columns), this subquery is called a row subquery.

Commonly used operators: = , <> , IN , NOT IN

case:

A. Query the same employee information as "Zhang Wuji" with the same salary and immediate leadership;

This requirement can also be broken down into two steps:

①. Query the salary and direct leadership of "Zhang Wuji"

select salary, managerid from emp where name = '张无忌';

②. Query the same employee information as "Zhang Wuji" with the same salary and direct leadership;

select * from emp where (salary,managerid) = (select salary, managerid from emp where name = '张无忌');

6.5 Table subqueries

The result returned by a subquery is multiple rows and multiple columns. This kind of subquery is called a table subquery.

Commonly used operators: IN 

case:

A. Query the employee information with the same position and salary as "Luzhangke" and "Song Yuanqiao"

Decomposed into two steps:

①. Query the positions and salaries of "Luzhangke" and "Song Yuanqiao"

select job, salary from emp where name = '鹿杖客' or name = '宋远桥';

②. Query the employee information with the same position and salary as "Luzhangke" and "Song Yuanqiao"

select * from emp where (job,salary) in ( select job, salary from emp where name = '鹿杖客' or name = '宋远桥' );

B. Query the employee information and department information whose entry date is after "2006-01-01"

Decomposed into two steps:

①. Employee information whose entry date is after "2006-01-01"

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

②. Query this part of employees, the corresponding department information;

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

Seven, multi-table query case practice

Data environment preparation:

create table salgrade(
    grade int,
    losal int,
    hisal int
) comment '薪资等级表';

insert into salgrade values (1,0,3000);
insert into salgrade values (2,3001,5000);
insert into salgrade values (3,5001,8000);
insert into salgrade values (4,8001,10000);
insert into salgrade values (5,10001,15000);
insert into salgrade values (6,15001,20000);
insert into salgrade values (7,20001,25000);
insert into salgrade values (8,25001,30000);

        In this case, we mainly use the multi-table query syntax explained above to complete the following 12 requirements, and here are mainly three tables involved: emp employee table, dept department table, salgrade salary grade table .

-- 1. 查询员工的姓名、年龄、职位、部门信息 (隐式内连接)
-- 表: emp , dept
-- 连接条件: emp.dept_id = dept.id

select e.name , e.age , e.job , d.name from emp e , dept d where e.dept_id = d.id;


-- 2. 查询年龄小于30岁的员工的姓名、年龄、职位、部门信息(显式内连接)
-- 表: emp , dept
-- 连接条件: emp.dept_id = dept.id

select e.name , e.age , e.job , d.name from emp e inner join dept d on e.dept_id = d.id where e.age < 30;


-- 3. 查询拥有员工的部门ID、部门名称
-- 表: emp , dept
-- 连接条件: emp.dept_id = dept.id

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


-- 4. 查询所有年龄大于40岁的员工, 及其归属的部门名称; 如果员工没有分配部门, 也需要展示出来
-- 表: emp , dept
-- 连接条件: emp.dept_id = dept.id
-- 外连接

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


-- 5. 查询所有员工的工资等级
-- 表: emp , salgrade
-- 连接条件 : emp.salary >= salgrade.losal and emp.salary <= salgrade.hisal

select e.* , s.grade , s.losal, s.hisal from emp e , salgrade s where e.salary >= s.losal and e.salary <= s.hisal;

select e.* , s.grade , s.losal, s.hisal from emp e , salgrade s where e.salary between s.losal and s.hisal;


-- 6. 查询 "研发部" 所有员工的信息及 工资等级
-- 表: emp , salgrade , dept
-- 连接条件 : emp.salary between salgrade.losal and salgrade.hisal , emp.dept_id = dept.id
-- 查询条件 : dept.name = '研发部'

select e.* , s.grade from emp e , dept d , salgrade s where e.dept_id = d.id and ( e.salary between s.losal and s.hisal ) and d.name = '研发部';


-- 7. 查询 "研发部" 员工的平均工资
-- 表: emp , dept
-- 连接条件 :  emp.dept_id = dept.id

select avg(e.salary) from emp e, dept d where e.dept_id = d.id and d.name = '研发部';


-- 8. 查询工资比 "灭绝" 高的员工信息。
-- a. 查询 "灭绝" 的薪资
select salary from emp where name = '灭绝';

-- b. 查询比她工资高的员工数据
select * from emp where salary > ( select salary from emp where name = '灭绝' );


-- 9. 查询比平均薪资高的员工信息
-- a. 查询员工的平均薪资
select avg(salary) from emp;

-- b. 查询比平均薪资高的员工信息
select * from emp where salary > ( select avg(salary) from emp );


-- 10. 查询低于本部门平均工资的员工信息

-- a. 查询指定部门平均薪资  1
select avg(e1.salary) from emp e1 where e1.dept_id = 1;
select avg(e1.salary) from emp e1 where e1.dept_id = 2;

-- b. 查询低于本部门平均工资的员工信息
select * from emp e2 where e2.salary < ( select avg(e1.salary) from emp e1 where e1.dept_id = e2.dept_id );


-- 11. 查询所有的部门信息, 并统计部门的员工人数
select d.id, d.name , ( select count(*) from emp e where e.dept_id = d.id ) '人数' from dept d;

select count(*) from emp where dept_id = 1;


-- 12. 查询所有学生的选课情况, 展示出学生名称, 学号, 课程名称
-- 表: student , course , student_course
-- 连接条件: student.id = student_course.studentid , course.id = student_course.courseid

select s.name , s.no , c.name from student s , student_course sc , course c where s.id = sc.studentid and sc.courseid = c.id ;

Previous article: [MySQL | Basics] 03. MySQL Constraints_Stars.Sky's Blog-CSDN Blog

Next article: [MySQL | Basics] 05. Detailed Explanation of MySQL Transaction_Stars.Sky's Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/weixin_46560589/article/details/130135049