复合查询和内外连接

文章目录

  • 1. 简单查询
  • 2. 多表查询
    • 2.1 显示雇员名、雇员工资以及所在部门的名字
    • 2.2 显示部门号为10的部门名,员工名和工资
    • 2.3 显示各个员工的姓名,工资,及工资级别
  • 3. 自连接
  • 4. 子查询
    • 4.1 where后的子查询
      • 4.1.1 单行子查询
      • 4.1.2 多行子查询 (in, all, any)
      • 4.1.3 多列子查询
    • 4.2 from后的子查询
    • 4.3 合并查询
  • 5. 内外连接
    • 5.1 内连接
    • 5.2 左外连接
    • 5.3 右外连接

1. 简单查询

先做几个简单查询的题目,使用下面的emp表

image-20241126194302041

查询工资高于2000或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J

mysql> select * from emp where (sal > 2000 or job = "MANAGER") and ename like "J%";
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno  | ename | job     | mgr  | hiredate            | sal     | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL |     20 |
+--------+-------+---------+------+---------------------+---------+------+--------+
-- 也可以写成这样
select * from emp where (sal > 2000 or job = "MANAGER") and left(ename,1)='J';

按照部门号升序而雇员的工资降序排序

mysql> select ename, deptno, sal from emp order by deptno asc, sal desc;
+--------+--------+---------+
| ename  | deptno | sal     |
+--------+--------+---------+
| KING   |     10 | 5000.00 |
| CLARK  |     10 | 2450.00 |
| MILLER |     10 | 1300.00 |
| SCOTT  |     20 | 3000.00 |
| FORD   |     20 | 3000.00 |
| JONES  |     20 | 2975.00 |
| ADAMS  |     20 | 1100.00 |
| SMITH  |     20 |  800.00 |
| BLAKE  |     30 | 2850.00 |
| ALLEN  |     30 | 1600.00 |
| TURNER |     30 | 1500.00 |
| WARD   |     30 | 1250.00 |
| MARTIN |     30 | 1250.00 |
| JAMES  |     30 |  950.00 |
+--------+--------+---------+
14 rows in set (0.00 sec)

使用年薪进行降序排序

-- 年薪计算用sal*12+comm,由于有的列comm为null,所以这里要检测一下
mysql> select ename, sal+ifnull(comm,0) total from emp order by total desc;
+--------+---------+
| ename  | total   |
+--------+---------+
| KING   | 5000.00 |
| SCOTT  | 3000.00 |
| FORD   | 3000.00 |
| JONES  | 2975.00 |
| BLAKE  | 2850.00 |
| MARTIN | 2650.00 |
| CLARK  | 2450.00 |
| ALLEN  | 1900.00 |
| WARD   | 1750.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| ADAMS  | 1100.00 |
| JAMES  |  950.00 |
| SMITH  |  800.00 |
+--------+---------+
14 rows in set (0.00 sec)

显示工资最高的员工的名字和工作岗位

mysql> select max(sal) from emp;
+----------+
| max(sal) |
+----------+
|  5000.00 |
+----------+
1 row in set (0.00 sec)

mysql> select ename, sal, deptno from emp where sal = 5000;
+-------+---------+--------+
| ename | sal     | deptno |
+-------+---------+--------+
| KING  | 5000.00 |     10 |
+-------+---------+--------+
1 row in set (0.00 sec)

-- 可以嵌套查询
mysql> select ename, sal, deptno from emp where sal = (select max(sal) from emp);
+-------+---------+--------+
| ename | sal     | deptno |
+-------+---------+--------+
| KING  | 5000.00 |     10 |
+-------+---------+--------+
1 row in set (0.00 sec)

显示工资高于平均工资的员工信息

mysql> select empno, ename, job, sal from emp where sal > (select avg(sal) from emp);
+--------+-------+-----------+---------+
| empno  | ename | job       | sal     |
+--------+-------+-----------+---------+
| 007566 | JONES | MANAGER   | 2975.00 |
| 007698 | BLAKE | MANAGER   | 2850.00 |
| 007782 | CLARK | MANAGER   | 2450.00 |
| 007788 | SCOTT | ANALYST   | 3000.00 |
| 007839 | KING  | PRESIDENT | 5000.00 |
| 007902 | FORD  | ANALYST   | 3000.00 |
+--------+-------+-----------+---------+
6 rows in set (0.00 se

显示每个部门的平均工资和最高工资

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

显示平均工资低于2000的部门号和它的平均工资

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

显示每种岗位的雇员总数,平均工资

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

2. 多表查询

现在又有多出来的两张表,进行多表查询

image-20241126211859587

image-20241126211917125

2.1 显示雇员名、雇员工资以及所在部门的名字

显然要用到emp表和dept表,下面的操作叫做求两个表的笛卡尔积
从第一张表取出每一条记录,和第二张表的所有记录进行组合。本质是进行穷举

mysql> select * from emp, dept;
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
| empno  | ename  | job       | mgr  | hiredate            | sal     | comm    | deptno | deptno | dname      | loc      |
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 | 800.00  | NULL    |     20 |     10 | ACCOUNTING | NEW YORK |
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 | 800.00  | NULL    |     20 |     20 | RESEARCH   | DALLAS   |
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 | 800.00  | NULL    |     20 |     30 | SALES      | CHICAGO  |
| 007369 | SMITH  | CLERK     | 7902 | 1980-12-17 00:00:00 | 800.00  | NULL    |     20 |     40 | OPERATIONS | BOSTON   |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00  |     30 |     10 | ACCOUNTING | NEW YORK |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00  |     30 |     20 | RESEARCH   | DALLAS   |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00  |     30 |     30 | SALES      | CHICAGO  |
| 007499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00  |     30 |     40 | OPERATIONS | BOSTON   |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00  |     30 |     10 | ACCOUNTING | NEW YORK |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00  |     30 |     20 | RESEARCH   | DALLAS   |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00  |     30 |     30 | SALES      | CHICAGO  |
| 007521 | WARD   | SALESMAN  | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00  |     30 |     40 | OPERATIONS | BOSTON   |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL    |     20 |     10 | ACCOUNTING | NEW YORK |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL    |     20 |     20 | RESEARCH   | DALLAS   |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL    |     20 |     30 | SALES      | CHICAGO  |
| 007566 | JONES  | MANAGER   | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL    |     20 |     40 | OPERATIONS | BOSTON   |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |     10 | ACCOUNTING | NEW YORK |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |     20 | RESEARCH   | DALLAS   |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |     30 | SALES      | CHICAGO  |
| 007654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 |     30 |     40 | OPERATIONS | BOSTON   |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL    |     30 |     10 | ACCOUNTING | NEW YORK |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL    |     30 |     20 | RESEARCH   | DALLAS   |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL    |     30 |     30 | SALES      | CHICAGO  |
| 007698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL    |     30 |     40 | OPERATIONS | BOSTON   |
......
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
56 rows in set (1.22 sec)

显然有重复显示的,例如对于SMITH来讲,只需要显示dept.deptno=20的那一行,所以需要加限制条件

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

按照题目要求进行显示

mysql> select ename, sal, 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.15 sec)

2.2 显示部门号为10的部门名,员工名和工资

mysql> select 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.16 sec)

2.3 显示各个员工的姓名,工资,及工资级别

这里要用到salgrade

mysql> select ename, sal, grade, losal, hisal from emp, salgrade hisal where sal between losal and hisal;
+--------+---------+-------+-------+-------+
| ename  | sal     | grade | losal | hisal |
+--------+---------+-------+-------+-------+
| SMITH  | 800.00  |     1 |   700 |  1200 |
| ALLEN  | 1600.00 |     3 |  1401 |  2000 |
| WARD   | 1250.00 |     2 |  1201 |  1400 |
| JONES  | 2975.00 |     4 |  2001 |  3000 |
| MARTIN | 1250.00 |     2 |  1201 |  1400 |
| BLAKE  | 2850.00 |     4 |  2001 |  3000 |
| CLARK  | 2450.00 |     4 |  2001 |  3000 |
| SCOTT  | 3000.00 |     4 |  2001 |  3000 |
| KING   | 5000.00 |     5 |  3001 |  9999 |
| TURNER | 1500.00 |     3 |  1401 |  2000 |
| ADAMS  | 1100.00 |     1 |   700 |  1200 |
| JAMES  | 950.00  |     1 |   700 |  1200 |
| FORD   | 3000.00 |     4 |  2001 |  3000 |
| MILLER | 1300.00 |     2 |  1201 |  1400 |
+--------+---------+-------+-------+-------+
14 rows in set (0.12 sec)

3. 自连接

也可以自己连接自己,用dept表实例

-- 这样是不行的
mysql> select * from dept, dept;
1066 - Not unique table/alias: 'dept'

-- 需要取别名
mysql> select * from dept t1, dept t2;
+--------+------------+----------+--------+------------+----------+
| deptno | dname      | loc      | deptno | dname      | loc      |
+--------+------------+----------+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |     10 | ACCOUNTING | NEW YORK |
|     30 | SALES      | CHICAGO  |     10 | ACCOUNTING | NEW YORK |
|     40 | OPERATIONS | BOSTON   |     10 | ACCOUNTING | NEW YORK |
|     10 | ACCOUNTING | NEW YORK |     20 | RESEARCH   | DALLAS   |
|     20 | RESEARCH   | DALLAS   |     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |     20 | RESEARCH   | DALLAS   |
|     40 | OPERATIONS | BOSTON   |     20 | RESEARCH   | DALLAS   |
|     10 | ACCOUNTING | NEW YORK |     30 | SALES      | CHICAGO  |
|     20 | RESEARCH   | DALLAS   |     30 | SALES      | CHICAGO  |
|     30 | SALES      | CHICAGO  |     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |     30 | SALES      | CHICAGO  |
|     10 | ACCOUNTING | NEW YORK |     40 | OPERATIONS | BOSTON   |
|     20 | RESEARCH   | DALLAS   |     40 | OPERATIONS | BOSTON   |
|     30 | SALES      | CHICAGO  |     40 | OPERATIONS | BOSTON   |
|     40 | OPERATIONS | BOSTON   |     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+--------+------------+----------+
16 rows in set (0.15 sec)

显示员工FORD的上级领导的编号和姓名

-- 可以使用子查询
mysql> select empno, ename from emp where empno=(select mgr from emp where ename='FORD');
+--------+-------+
| empno  | ename |
+--------+-------+
| 007566 | JONES |
+--------+-------+
1 row in set (0.13 sec)
-- 自连接
mysql> select e2.empno, e2.ename from emp e1, emp e2 where e1.mgr=e2.empno and e1.ename='FORD';
+--------+-------+
| empno  | ename |
+--------+-------+
| 007566 | JONES |
+--------+-------+
1 row in set (0.14 sec)

4. 子查询

子查询(Subquery)也被称为嵌套查询(Nested Query)。它是一个嵌套在另一个 SQL 查询(通常是SELECT语句)中的完整 SQL 查询。

4.1 where后的子查询

4.1.1 单行子查询

子查询返回一行记录

显示SMITH同一部门的员工

-- 返回一行记录
mysql> select deptno from emp where ename = 'SMITH';
+--------+
| deptno |
+--------+
|     20 |
+--------+
1 row in set (0.06 sec)

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.07 sec)

4.1.2 多行子查询 (in, all, any)

子查询返回多行记录

使用in关键字查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的

-- 返回多行记录
mysql> select job from emp where deptno = 10;
+-----------+
| job       |
+-----------+
| MANAGER   |
| PRESIDENT |
| CLERK     |
+-----------+
3 rows in set (0.08 sec)

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

注:如果想要加上部门名称,可以这样写,就是上面的多表查询

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

-- 实际上,from后面也可以跟子查询,因为子查询返回的是一个完整的表, 下面返回结果与上面是一样的
select ename, job, sal, tmp.deptno, dname from (select ename, job, sal, deptno from emp where job in (select job from emp where deptno = 10) and deptno != 10) as tmp, dept where dept.deptno = tmp.deptno;

使用all关键字显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号

mysql> select sal from emp where deptno = 30;
+---------+
| sal     |
+---------+
| 1600.00 |
| 1250.00 |
| 1250.00 |
| 2850.00 |
| 1500.00 |
| 950.00  |
+---------+
6 rows in set (0.10 sec)

mysql> select ename, sal, deptno from emp where 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.10 sec)

-- 当然也可以这样写
mysql> select ename, sal, deptno from emp where sal > (select max(sal) from emp where deptno = 30);

使用any关键字: 显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)

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.11 sec)

4.1.3 多列子查询

子查询返回多列记录

查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人

mysql> select deptno, job from emp where ename = 'SMITH';
+--------+-------+
| deptno | job   |
+--------+-------+
|     20 | CLERK |
+--------+-------+
1 row in set (0.13 sec)

mysql> select * from emp where (deptno, job) = (select deptno, 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.14 sec)

-- 这里也可用in,这样就是多行,多列子查询了
select * from emp where (deptno, job) = (select deptno, job from emp where ename = 'SMITH') and ename != 'SMITH';

4.2 from后的子查询

子查询语句出现在from子句中,把一个子查询当做一个临时表使用。

显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资

mysql> select deptno, avg(sal) avg from emp group by deptno;
+--------+-------------+
| deptno | avg         |
+--------+-------------+
|     10 | 2916.666667 |
|     20 | 2175.000000 |
|     30 | 1566.666667 |
+--------+-------------+
3 rows in set (0.11 sec)

mysql> select ename, t1.deptno, sal, avg from (select deptno, avg(sal) avg from emp group by deptno) t1, emp t2 where t1.deptno = t2.deptno and sal > avg;
+-------+--------+---------+-------------+
| ename | deptno | sal     | avg         |
+-------+--------+---------+-------------+
| 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.10 sec)

-- 如果想要查询部门名称,需要再将上面的结果放到from子句后面,再套一层。不过嵌套太多了,可读性很差
mysql> select ename, t3.deptno, sal, avg, t4.dname from (select ename, t1.deptno, sal, avg from (select deptno, avg(sal) avg from emp group by deptno) t1, emp t2 where t1.deptno = t2.deptno and sal > avg) as t3, dept as t4 where t3.deptno = t4.deptno;
+-------+--------+---------+-------------+------------+
| ename | deptno | sal     | avg         | dname      |
+-------+--------+---------+-------------+------------+
| ALLEN |     30 | 1600.00 | 1566.666667 | SALES      |
| JONES |     20 | 2975.00 | 2175.000000 | RESEARCH   |
| BLAKE |     30 | 2850.00 | 1566.666667 | SALES      |
| SCOTT |     20 | 3000.00 | 2175.000000 | RESEARCH   |
| KING  |     10 | 5000.00 | 2916.666667 | ACCOUNTING |
| FORD  |     20 | 3000.00 | 2175.000000 | RESEARCH   |
+-------+--------+---------+-------------+------------+
6 rows in set (0.11 sec)

查找每个部门工资最高的人的姓名、工资、部门、最高工资

mysql> select max(sal) as max, deptno from emp group by deptno;
+---------+--------+
| max     | deptno |
+---------+--------+
| 5000.00 |     10 |
| 3000.00 |     20 |
| 2850.00 |     30 |
+---------+--------+
3 rows in set (0.12 sec)

mysql> select ename, sal, t1.deptno, max from emp as t1, (select max(sal) as max, deptno from emp group by deptno) as t2 where t1.deptno=t2.deptno and t1.sal = t2.max;
+-------+---------+--------+---------+
| ename | sal     | deptno | max     |
+-------+---------+--------+---------+
| 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.13 sec)

显示每个部门的信息(部门名,编号,地址)和人员数量

mysql> select t1.deptno, dname, loc, cnt from dept as t1, (select count(*) as cnt, deptno from emp group by deptno) as t2 where t1.deptno=t2.deptno;
+--------+------------+----------+-----+
| deptno | dname      | loc      | cnt |
+--------+------------+----------+-----+
|     10 | ACCOUNTING | NEW YORK |   3 |
|     20 | RESEARCH   | DALLAS   |   5 |
|     30 | SALES      | CHICAGO  |   6 |
+--------+------------+----------+-----+
3 rows in set (0.12 sec)

-- 使用多表查询,由于mysql的限制,所以group by后面要加上这些多余的限制条件
mysql> select dept.deptno, dname, loc, count(*) cnt from emp, dept where emp.deptno = dept.deptno group by dept.deptno, dname, loc;

4.3 合并查询

两个关键字: unionunion allunionselect语句后的执行结果取并集,union all不做去重操作

将工资大于2500或职位是MANAGER的人找出来

mysql> select * from emp where sal > 2500 union select * from emp where job = 'MANGER';
+-------+-------+-----------+------+---------------------+---------+------+--------+
| 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 |
+-------+-------+-----------+------+---------------------+---------+------+--------+
5 rows in set (0.11 sec)

mysql> select * from emp where sal > 2500 union all select * from emp where job = 'MANGER';
+-------+-------+-----------+------+---------------------+---------+------+--------+
| 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 |
+-------+-------+-----------+------+---------------------+---------+------+--------+
5 rows in set (0.12 sec)

-- 注意: select 后面需要有相同的列
mysql> select * from emp where sal > 2500 union all select ename from emp where job = 'MANGER';
1222 - The used SELECT statements have a different number of columns

5. 内外连接

5.1 内连接

内连接可以看作是对笛卡尔积结果集的筛选。
从实现的角度来看,数据库在执行内连接时,可能会先计算两个表的笛卡尔积(在内部实现中,这可能是一种优化后的计算方式),然后根据连接条件(如ON子句指定的条件)来过滤掉不符合要求的行组合,最终得到内连接的结果。

语法:

select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;

显示SMITH的名字和部门名称

-- 使用前面笛卡尔积加筛选条件的写法
mysql> select ename, dname from emp, dept where emp.deptno=dept.deptno and emp.ename = 'SMITH';
+-------+----------+
| ename | dname    |
+-------+----------+
| SMITH | RESEARCH |
+-------+----------+
1 row in set (0.13 sec)

-- 内连接
mysql> select ename, dname from emp inner join dept on emp.deptno = dept.deptno and ename = 'SMITH';
+-------+----------+
| ename | dname    |
+-------+----------+
| SMITH | RESEARCH |
+-------+----------+
1 row in set (0.12 sec)
-- 注,上面的and也可以换成where,意味着先分好一个表后,再按where后的条件筛选

5.2 左外连接

返回左表(在FROM子句中位于LEFT JOIN关键字左边的表)中的所有行,以及右表(在LEFT JOIN关键字右边的表)中与左表连接条件匹配的行。如果右表中没有匹配的行,则在结果集中相应的列将填充为NULL值。

语法:

select 字段名 from 表名1 left join 表名2 on 连接条件

假设有下面两张表

mysql> select * from stu;
+----+------+
| id | name |
+----+------+
|  1 | jack |
|  2 | tom  |
|  3 | kity |
|  4 | nono |
+----+------+
4 rows in set (0.11 sec)

mysql> select * from exam;
+----+-------+
| id | grade |
+----+-------+
|  1 |    56 |
|  2 |    76 |
| 11 |     8 |
+----+-------+
3 rows in set (0.11 sec)

查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来

mysql> select * from stu left join exam on stu.id = exam.id;
+----+------+------+-------+
| id | name | id   | grade |
+----+------+------+-------+
|  1 | jack |    1 |    56 |
|  2 | tom  |    2 |    76 |
|  3 | kity | NULL | NULL  |
|  4 | nono | NULL | NULL  |
+----+------+------+-------+
4 rows in set (0.13 sec)

5.3 右外连接

返回右表(在FROM子句中位于RIGHT JOIN关键字右边的表)中的所有行,以及左表(在RIGHT JOIN关键字左边的表)中与右表连接条件匹配的行。如果左表中没有匹配的行,在结果集中相应的列会填充为NULL值。

语法:

select 字段名 from 表名1 right join 表名2 on 连接条件

继续使用5.3中的表

对stu表和exam表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要显示出来

mysql> select * from exam right join stu on exam.id = stu.id;
+------+-------+----+------+
| id   | grade | id | name |
+------+-------+----+------+
|    1 |    56 |  1 | jack |
|    2 |    76 |  2 | tom  |
| NULL | NULL  |  3 | kity |
| NULL | NULL  |  4 | nono |
+------+-------+----+------+
4 rows in set (0.11 sec)

使用emp表和dept表,列出部门名称和这些部门的员工信息,同时列出没有员工的部

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java八股-分布式服务的接口幂等性如何设计?

文章目录 接口幂等token Redis分布式锁 原文视频链接&#xff1a;讲解的流程特别清晰&#xff0c;易懂&#xff0c;收获巨大 【新版Java面试专题视频教程&#xff0c;java八股文面试全套真题深度详解&#xff08;含大厂高频面试真题&#xff09;】 https://www.bilibili.com/…

Windows Serv 2019 虚拟机 安装Oracle19c,图文详情(超详细)

1、下载安装文件 Oracle官网下载直链&#xff1a;https://www.oracle.com/database/technologies/oracle-database-software-downloads.html#db_ee 夸克网盘下载&#xff1a;https://pan.quark.cn/s/1460a663ee83 2、新建 Windows Server 2019 虚拟机 &#xff08;超详细&a…

时间的礼物:如何珍视每一刻

《时间的礼物&#xff1a;如何珍视每一刻》 夫时间者&#xff0c;宇宙之精髓&#xff0c;生命之经纬&#xff0c;悄无声息而流转不息&#xff0c;如织锦之细线&#xff0c;串联古今&#xff0c;贯穿万物。 人生短暂&#xff0c;犹如白驹过隙&#xff0c;倏忽而逝&#xff0c;…

FreeRTOS之vTaskStartScheduler实现分析

FreeRTOS之vTaskStartScheduler实现分析 1 FreeRTOS源码下载地址2 函数接口2.1 函数接口2.2 函数参数简介3 vTaskDelete的调用关系3.1 调用关系3.2 调用关系示意图 4 函数源码分析4.1 vTaskStartScheduler4.2 prvCreateIdleTasks4.2.1 prvCreateIdleTasks4.2.2 xTaskCreate 4.3…

NLP论文速读(EMNLP2024)|多风格可控生成的动态多奖励权重

论文速读|Dynamic Multi-Reward Weighting for Multi-Style Controllable Generation 论文信息&#xff1a; 简介&#xff1a; 本文探讨了文本风格在沟通中的重要性&#xff0c;指出文本风格传达了除原始语义内容之外的多种信息&#xff0c;如人际关系动态&#xff08;例如正式…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…

Dockerfile打包部署

Dockerfile打包 先找到打包完的目录下创建一个Dockerfile文件 touch Dockerfile 进去文件内编写 vim Dockerfile # 基础镜像 FROM openjdk:8 # author MAINTAINER yxh # 挂载目录 VOLUME /home/project # 创建目录 RUN mkdir -p /home/project # 指定路径 WORKDIR /home/pr…

鸿蒙学习使用模拟器运行应用(开发篇)

文章目录 1、系统类型和运行环境要求2、创建模拟器3、启动和关闭模拟器4、安装应用程序包和上传文件QA:在Windows电脑上启动模拟器&#xff0c;提示未开启Hyper-V 1、系统类型和运行环境要求 Windows 10 企业版、专业版或教育版及以上&#xff0c;且操作系统版本不低于10.0.18…

数组学习后记——递归

数组这块学得有点乱,条理性欠佳。这次正好总结一下。上周的课堂内容没有更新, 因为小白自己也还没来得及吸收呢qwq。也解释一下为什么文中有这么多例题。因为我呢喜欢就着题去分析和学习,直接灌输知识不太能理解,有例子就能及时检验和应用了的。 先看看B3817 基础的双数组…

每天五分钟深度学习:神经网络的前向传播的计算过程(单样本)

本文重点 本节课程我们学习神经网络的输出是如何计算的,这个过程叫做神经网络的前向传播。 神经网络的结构 如上所示是一个具有单隐藏层的神经网络,其中输入层不算神经网络的层数。 在这个神经网络中,x表示输入特征,a表示每个神经元的输出,W表示权重参数。 神经网络的…

C++——多态(下)

目录 引言 多态 4.多态的原理 4.1 虚函数表指针 4.2 多态的原理 5.单继承和多继承关系的虚函数表 5.1 单继承中的虚函数表 5.2 多继承中的虚函数表 结束语 引言 接下来我们继续学习多态。 没有阅读多态&#xff08;上&#xff09;的可以点击下面的链接哦~ C——多态…

【CSS in Depth 2 精译_061】9.4 CSS 中的模式库 + 9.5 本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第九章 CSS 的模块化与作用域】 ✔️ 9.1 模块的定义 9.1.1 模块和全局样式9.1.2 一个简单的 CSS 模块9.1.3 模块的变体9.1.4 多元素模块 9.2 将模块组合为更大的结构 9.2.1 模块中多个职责的拆分…

DHCP服务(包含配置过程)

目录 一、 DHCP的定义 二、 使用DHCP的好处 三、 DHCP的分配方式 四、 DHCP的租约过程 1. 客户机请求IP 2. 服务器响应 3. 客户机选择IP 4. 服务器确定租约 5. 重新登录 6. 更新租约 五、 DHCP服务配置过程 一、 DHCP的定义 DHCP&#xff08;Dynamic Host Configur…

技术实践 | AI 安全:通过大模型解决高危WEB应用识别问题

一、引言 在日常企业安全能力建设中&#xff0c;收敛企业外网高危资产&#xff0c;以保障公司外部安全是企业安全的重要工作。WEB 高危服务&#xff08;如&#xff1a;管理后台、内部系统等&#xff09;外开是企业所面临的一个重要风险。针对该风险&#xff0c;传统的方式是基…

C 语言函数递归探秘:从基础概念到复杂问题求解的进阶之路

我的个人主页 我的专栏&#xff1a;C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 目录 什么是函数递归递归的基本组成递归的工作原理递归的优缺点递归的经典案例 5.1 阶乘计算5.2 斐波那契数列5.3 汉诺塔问题5.4 二分查找 递归的高级…

多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测

多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现…

「Mac畅玩鸿蒙与硬件33」UI互动应用篇10 - 数字猜谜游戏

本篇将带你实现一个简单的数字猜谜游戏。用户输入一个数字&#xff0c;应用会判断是否接近目标数字&#xff0c;并提供提示“高一点”或“低一点”&#xff0c;直到用户猜中目标数字。这个小游戏结合状态管理和用户交互&#xff0c;是一个入门级的互动应用示例。 关键词 UI互…

el-table根据接口返回某一个字段合并行

根据名称相同合并行 <template><div><el-table :data"responseSearchIntegralAddData" :span-method"objectSpanMethod1" border style"width: 100%"><el-table-column prop"integralTypeName" label"名称…

Linux系统之fuser命令的基本使用

Linux系统之fuser命令的基本使用 一、fuser命令介绍二、fuser命令使用帮助2.1 help帮助信息2.1 基本语法①通用选项②文件/设备相关选项③网络相关选项④进程操作选项⑤其他选项 三、fuser命令的基本使用3.1 查找挂载点的进程3.2 查看指定设备进程信息3.3 查找监听特定端口的进…

守护进程

目录 守护进程 前台进程 后台进程 session&#xff08;进程会话&#xff09; 前台任务和后台任务比较好 本质 绘画和终端都关掉了&#xff0c;那些任务仍然在 bash也退了&#xff0c;然后就托孤了 ​编辑 守护进程化---不想受到任何用户登陆和注销的影响​编辑 如何…