Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL复合查询

MySQL复合查询的具体使用

作者:Oo৹Oo৹Oo৹

本文介绍了MySQL复合查询的基本操作,包括多表查询和复杂条件查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. 复合查询

前面所介绍的查询都是对 MySQL 一张表进行查询,但在实际应用中,我们往往需要从多张表中获取数据,这时就需要使用复合查询

1.1 基本查询回顾

mysql> select * from emp  where (sal > 500 or job = 'MANAGER') and substring(ename,1,1) = 'J';
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno  | ename | job     | mgr  | hiredate            | sal     | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
| 007900 | JAMES | CLERK   | 7698 | 1981-12-03 00:00:00 |  950.00 | NULL |     30 |
+--------+-------+---------+------+---------------------+---------+------+--------+
2 rows in set (0.00 sec)

mysql> 
mysql> select * from emp order by deptno asc,sal desc;
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| empno  | ename  | job       | mgr  | hiredate            | sal     | comm    | deptno |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| 007839 | KING   | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 |    NULL |     10 |
| 007782 | CLARK  | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 |    NULL |     10 |
| 007934 | MILLER | CLERK     | 7782 | 1982-01-23 00:00:00 | 1300.00 |    NULL |     10 |
| 007788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 |    NULL |     20 |
| 007902 | FORD   | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 |    NULL |     20 |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 |    NULL |     20 |
| 007876 | ADAMS  | CLERK     | 7788 | 1987-05-23 00:00:00 | 1100.00 |    NULL |     20 |
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 |  800.00 |    NULL |     20 |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 |    NULL |     30 |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 |  300.00 |     30 |
| 007844 | TURNER | SALESMAN  | 7698 | 1981-09-08 00:00:00 | 1500.00 |    0.00 |     30 |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 |  500.00 |     30 |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |
| 007900 | JAMES  | CLERK     | 7698 | 1981-12-03 00:00:00 |  950.00 |    NULL |     30 |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
14 rows in set (0.00 sec)

mysql> 
mysql> select *,sal*12+ifnull(comm,0) as annual_sal from emp order by annual_sal desc;
+--------+--------+-----------+------+---------------------+---------+---------+--------+------------+
| empno  | ename  | job       | mgr  | hiredate            | sal     | comm    | deptno | annual_sal |
+--------+--------+-----------+------+---------------------+---------+---------+--------+------------+
| 007839 | KING   | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 |    NULL |     10 |   60000.00 |
| 007788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 |    NULL |     20 |   36000.00 |
| 007902 | FORD   | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 |    NULL |     20 |   36000.00 |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 |    NULL |     20 |   35700.00 |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 |    NULL |     30 |   34200.00 |
| 007782 | CLARK  | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 |    NULL |     10 |   29400.00 |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 |  300.00 |     30 |   19500.00 |
| 007844 | TURNER | SALESMAN  | 7698 | 1981-09-08 00:00:00 | 1500.00 |    0.00 |     30 |   18000.00 |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |   16400.00 |
| 007934 | MILLER | CLERK     | 7782 | 1982-01-23 00:00:00 | 1300.00 |    NULL |     10 |   15600.00 |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 |  500.00 |     30 |   15500.00 |
| 007876 | ADAMS  | CLERK     | 7788 | 1987-05-23 00:00:00 | 1100.00 |    NULL |     20 |   13200.00 |
| 007900 | JAMES  | CLERK     | 7698 | 1981-12-03 00:00:00 |  950.00 |    NULL |     30 |   11400.00 |
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 |  800.00 |    NULL |     20 |    9600.00 |
+--------+--------+-----------+------+---------------------+---------+---------+--------+------------+
14 rows in set (0.00 sec)

mysql> 

注:comm 列表示佣金,全称 Commission

mysql> select ename,job from emp where sal = (select max(sal) from emp);
+-------+-----------+
| ename | job       |
+-------+-----------+
| KING  | PRESIDENT |
+-------+-----------+
1 row in set (0.00 sec)

mysql> 
mysql> select *from emp where sal > (select avg(sal) from emp);
+--------+-------+-----------+------+---------------------+---------+------+--------+
| empno  | ename | job       | mgr  | hiredate            | sal     | comm | deptno |
+--------+-------+-----------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
| 007698 | BLAKE | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL |     30 |
| 007782 | CLARK | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL |     10 |
| 007788 | SCOTT | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL |     20 |
| 007839 | KING  | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL |     10 |
| 007902 | FORD  | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL |     20 |
+--------+-------+-----------+------+---------------------+---------+------+--------+
6 rows in set (0.00 sec)

mysql> 
mysql> select deptno,avg(sal) as avg_sal,max(sal) as max_sal from emp group by deptno;
+--------+-------------+---------+
| deptno | avg_sal     | max_sal |
+--------+-------------+---------+
|     20 | 2175.000000 | 3000.00 |
|     30 | 1566.666667 | 2850.00 |
|     10 | 2916.666667 | 5000.00 |
+--------+-------------+---------+
3 rows in set (0.00 sec)

mysql> 
mysql> select deptno,avg(sal) avg_sal from emp group by deptno having avg(sal) < 2000;
+--------+-------------+
| deptno | avg_sal     |
+--------+-------------+
|     30 | 1566.666667 |
+--------+-------------+
1 row in set (0.00 sec)

mysql> 
mysql> select job,count(*) as total,avg(sal) as avg_sal from emp group by job;
+-----------+-------+-------------+
| job       | total | avg_sal     |
+-----------+-------+-------------+
| CLERK     |     4 | 1037.500000 |
| SALESMAN  |     4 | 1400.000000 |
| MANAGER   |     3 | 2758.333333 |
| ANALYST   |     2 | 3000.000000 |
| PRESIDENT |     1 | 5000.000000 |
+-----------+-------+-------------+
5 rows in set (0.00 sec)

mysql> 

1.2 多表查询

在进行多表查询的时候,其实本质上和单表查询是一样的,以下图中的 emp 和 dept 为例:

  1. 从第一张表中选出第一条记录,和第二张表中的所有记录进行组合
  2. 从第一张表中选取第二条记录,和第二张表中的所有记录进行组合
  3. 重复上述过程,直到第一张表中的所有记录都和第二张表的所有记录组合完毕
  4. 得到最终的组合记录表,现在就已经将两张表连接起来了
  5. 前面我们说过,“一切皆表” 的思维模式,在多表查询这里也同样适用,将多张表连接起来,看作是一张表
  6. 如果有过滤条件,按照条件对组合后的表进行筛选
  7. 显示最终结果

这个组合的过程和数学上的笛卡尔积类似

很明显,雇员名和雇员工资在 emp 表中,部门名字在 dept 表中,需要通过连接查询来实现

mysql> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.00 sec)

mysql> select ename,sal,dept.dname from emp,dept where emp.deptno = dept.deptno;
+--------+---------+------------+
| ename  | sal     | dname      |
+--------+---------+------------+
| SMITH  |  800.00 | RESEARCH   |
| ALLEN  | 1600.00 | SALES      |
| WARD   | 1250.00 | SALES      |
| JONES  | 2975.00 | RESEARCH   |
| MARTIN | 1250.00 | SALES      |
| BLAKE  | 2850.00 | SALES      |
| CLARK  | 2450.00 | ACCOUNTING |
| SCOTT  | 3000.00 | RESEARCH   |
| KING   | 5000.00 | ACCOUNTING |
| TURNER | 1500.00 | SALES      |
| ADAMS  | 1100.00 | RESEARCH   |
| JAMES  |  950.00 | SALES      |
| FORD   | 3000.00 | RESEARCH   |
| MILLER | 1300.00 | ACCOUNTING |
+--------+---------+------------+
14 rows in set (0.00 sec)

mysql> 
mysql> select dept.dname,ename,sal from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
+------------+--------+---------+
| dname      | ename  | sal     |
+------------+--------+---------+
| ACCOUNTING | CLARK  | 2450.00 |
| ACCOUNTING | KING   | 5000.00 |
| ACCOUNTING | MILLER | 1300.00 |
+------------+--------+---------+
3 rows in set (0.00 sec)

mysql> 
mysql> select * from salgrade;
+-------+-------+-------+
| grade | losal | hisal |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+
5 rows in set (0.01 sec)

mysql> select ename,sal,grade from emp,salgrade where emp.sal between losal and hisal order by grade;
+--------+---------+-------+
| ename  | sal     | grade |
+--------+---------+-------+
| SMITH  |  800.00 |     1 |
| ADAMS  | 1100.00 |     1 |
| JAMES  |  950.00 |     1 |
| WARD   | 1250.00 |     2 |
| MARTIN | 1250.00 |     2 |
| MILLER | 1300.00 |     2 |
| ALLEN  | 1600.00 |     3 |
| TURNER | 1500.00 |     3 |
| JONES  | 2975.00 |     4 |
| BLAKE  | 2850.00 |     4 |
| CLARK  | 2450.00 |     4 |
| SCOTT  | 3000.00 |     4 |
| FORD   | 3000.00 |     4 |
| KING   | 5000.00 |     5 |
+--------+---------+-------+
14 rows in set (0.00 sec)

mysql> 

1.3 自连接

自连接是指一张表与其自身进行连接查询

案例

使用子查询

mysql> select ename,empno from emp where empno = (select mgr from emp where ename = 'FORD');
+-------+--------+
| ename | empno  |
+-------+--------+
| JONES | 007566 |
+-------+--------+
1 row in set (0.00 sec)

mysql> 

使用多表查询(自查询)

mysql> select leader.ename,leader.deptno from emp leader,emp worker where leader.empno = worker.mgr and worker.ename = 'FORD';
+-------+--------+
| ename | deptno |
+-------+--------+
| JONES |     20 |
+-------+--------+
1 row in set (0.00 sec)

mysql> 

在上面的示例中使用自查询的时候,需要注意对表起别名,因为要区分两张表

mgr 是雇员的上级领导编号
empno 是雇员编号

1.4 子查询

子查询是指在另一个查询语句的 where 子句中出现的查询语句,也叫做嵌套查询(前面我们已经用过)

1.4.1 单行子查询

返回一行记录的子查询

mysql> select * from emp where deptno = (select deptno from emp where ename = 'SMITH');
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno  | ename | job     | mgr  | hiredate            | sal     | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007369 | SMITH | CLERK   | 7902 | 1980-12-17 00:00:00 |  800.00 | NULL |     20 |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL |     20 |
| 007876 | ADAMS | CLERK   | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL |     20 |
| 007902 | FORD  | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL |     20 |
+--------+-------+---------+------+---------------------+---------+------+--------+
5 rows in set (0.00 sec)

mysql> 

1.4.2 多行子查询

返回多行记录的子查询

mysql> select ename,job,sal,deptno from emp where deptno != 10 and job in (select job from emp where deptno = 10);
+-------+---------+---------+--------+
| ename | job     | sal     | deptno |
+-------+---------+---------+--------+
| SMITH | CLERK   |  800.00 |     20 |
| JONES | MANAGER | 2975.00 |     20 |
| BLAKE | MANAGER | 2850.00 |     30 |
| ADAMS | CLERK   | 1100.00 |     20 |
| JAMES | CLERK   |  950.00 |     30 |
+-------+---------+---------+--------+
5 rows in set (0.00 sec)

mysql> 
mysql> select ename,sal,deptno from emp where deptno != 30 and sal > all (select sal from emp where deptno = 30) ;
+-------+---------+--------+
| ename | sal     | deptno |
+-------+---------+--------+
| JONES | 2975.00 |     20 |
| SCOTT | 3000.00 |     20 |
| KING  | 5000.00 |     10 |
| FORD  | 3000.00 |     20 |
+-------+---------+--------+
4 rows in set (0.00 sec)

mysql> 
mysql> select ename,sal,deptno from emp where sal > any (select sal from emp where deptno = 30);
+--------+---------+--------+
| ename  | sal     | deptno |
+--------+---------+--------+
| ALLEN  | 1600.00 |     30 |
| WARD   | 1250.00 |     30 |
| JONES  | 2975.00 |     20 |
| MARTIN | 1250.00 |     30 |
| BLAKE  | 2850.00 |     30 |
| CLARK  | 2450.00 |     10 |
| SCOTT  | 3000.00 |     20 |
| KING   | 5000.00 |     10 |
| TURNER | 1500.00 |     30 |
| ADAMS  | 1100.00 |     20 |
| FORD   | 3000.00 |     20 |
| MILLER | 1300.00 |     10 |
+--------+---------+--------+
12 rows in set (0.00 sec)

mysql> 

1.4.3 多列子查询

单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句

mysql> select * from emp where deptno = (select deptno from emp where ename = 'SMITH') and job = (select job from emp where ename = 'SMITH') and ename != 'SMITH';
+--------+-------+-------+------+---------------------+---------+------+--------+
| empno  | ename | job   | mgr  | hiredate            | sal     | comm | deptno |
+--------+-------+-------+------+---------------------+---------+------+--------+
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL |     20 |
+--------+-------+-------+------+---------------------+---------+------+--------+
1 row in set (0.00 sec)

mysql> 

1.4.4 在 from 子句中使用子查询

子查询语句出现在 from 子句中,这时候子查询的结果会被当作一个临时表来使用,再次体现了 “一切皆表” 的思维模式

mysql> select ename,deptno,sal,dept_avg_sal from emp,
    -> (select deptno my_deptno,avg(sal) dept_avg_sal from emp group by deptno) tmp
    -> where emp.sal > tmp.dept_avg_sal and emp.deptno = tmp.my_deptno;
+-------+--------+---------+--------------+
| ename | deptno | sal     | dept_avg_sal |
+-------+--------+---------+--------------+
| ALLEN |     30 | 1600.00 |  1566.666667 |
| JONES |     20 | 2975.00 |  2175.000000 |
| BLAKE |     30 | 2850.00 |  1566.666667 |
| SCOTT |     20 | 3000.00 |  2175.000000 |
| KING  |     10 | 5000.00 |  2916.666667 |
| FORD  |     20 | 3000.00 |  2175.000000 |
+-------+--------+---------+--------------+
6 rows in set (0.00 sec)

mysql> select t1emp.ename,t1emp.deptno,t1emp.sal,t2emp.dept_avg_sal from
    -> (select ename,deptno,sal from emp) t1emp,
    -> (select deptno,avg(sal) dept_avg_sal from emp group by deptno) t2emp
    -> where t1emp.sal > t2emp.dept_avg_sal and t1emp.deptno = t2emp.deptno;
+-------+--------+---------+--------------+
| ename | deptno | sal     | dept_avg_sal |
+-------+--------+---------+--------------+
| ALLEN |     30 | 1600.00 |  1566.666667 |
| JONES |     20 | 2975.00 |  2175.000000 |
| BLAKE |     30 | 2850.00 |  1566.666667 |
| SCOTT |     20 | 3000.00 |  2175.000000 |
| KING  |     10 | 5000.00 |  2916.666667 |
| FORD  |     20 | 3000.00 |  2175.000000 |
+-------+--------+---------+--------------+
6 rows in set (0.00 sec)

mysql> 
mysql> select ename,sal,deptno,dept_max_sal from emp,
    -> (select max(sal) dept_max_sal,deptno tdeptno from emp group by deptno) tmp
    -> where sal = dept_max_sal and deptno = tdeptno;
+-------+---------+--------+--------------+
| ename | sal     | deptno | dept_max_sal |
+-------+---------+--------+--------------+
| BLAKE | 2850.00 |     30 |      2850.00 |
| SCOTT | 3000.00 |     20 |      3000.00 |
| KING  | 5000.00 |     10 |      5000.00 |
| FORD  | 3000.00 |     20 |      3000.00 |
+-------+---------+--------+--------------+
4 rows in set (0.00 sec)

mysql> 
mysql> select dname,dept.deptno,loc,tmp.total from dept, (select count(*) total,deptno from emp group by deptno) tmp where dept.deptno = tmp.deptno;

+------------+--------+----------+-------+
| dname      | deptno | loc      | total |
+------------+--------+----------+-------+
| ACCOUNTING |     10 | NEW YORK |     3 |
| RESEARCH   |     20 | DALLAS   |     5 |
| SALES      |     30 | CHICAGO  |     6 |
+------------+--------+----------+-------+
3 rows in set (0.01 sec)

mysql> 

1.4.5 合并查询

在实际应用中,为了合并多个 select 的执行结果,可以使用集合操作符 unionunion all

1.4.5.1 union

union 可以获得两个结果集的并集,会自动去掉结果集中的重复行

mysql> select * from emp where sal > 2500 union select * from emp where job = 'MANAGER';
+-------+-------+-----------+------+---------------------+---------+------+--------+
| empno | ename | job       | mgr  | hiredate            | sal     | comm | deptno |
+-------+-------+-----------+------+---------------------+---------+------+--------+
|  7566 | JONES | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
|  7698 | BLAKE | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL |     30 |
|  7788 | SCOTT | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL |     20 |
|  7839 | KING  | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL |     10 |
|  7902 | FORD  | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL |     20 |
|  7782 | CLARK | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL |     10 |
+-------+-------+-----------+------+---------------------+---------+------+--------+
6 rows in set (0.00 sec)

mysql> 

1.4.5.2 union all

union all 可以获取两个结果集的并集,不会去掉重复行

mysql> select * from emp where sal > 2500 union all select * from emp where job = 'MANAGER';
+-------+-------+-----------+------+---------------------+---------+------+--------+
| empno | ename | job       | mgr  | hiredate            | sal     | comm | deptno |
+-------+-------+-----------+------+---------------------+---------+------+--------+
|  7566 | JONES | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
|  7698 | BLAKE | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL |     30 |
|  7788 | SCOTT | ANALYST   | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL |     20 |
|  7839 | KING  | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL |     10 |
|  7902 | FORD  | ANALYST   | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL |     20 |
|  7566 | JONES | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
|  7698 | BLAKE | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL |     30 |
|  7782 | CLARK | MANAGER   | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL |     10 |
+-------+-------+-----------+------+---------------------+---------+------+--------+
8 rows in set (0.00 sec)

mysql> 

到此这篇关于MySQL复合查询的具体使用的文章就介绍到这了,更多相关MySQL复合查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文