当前位置: 首页 > news >正文

MySQL笔记---复合查询

1. Oracle 9i 经典测试表

在 Oracle 9i 中,最经典的测试表是默认演示用户SCOTT下的一套表,这些表设计简洁、关系清晰,常用于 SQL 语法练习、查询测试和教学演示。

接下来,我们也将以这一套表为基础给出应用示例:

-- 创建部门表(dept)
CREATE TABLE IF NOT EXISTS dept (deptno INT PRIMARY KEY COMMENT '部门编号',dname VARCHAR(14) NOT NULL COMMENT '部门名称',loc VARCHAR(13) NOT NULL COMMENT '部门所在地'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '部门信息表';-- 创建员工表(emp),包含自关联外键(经理编号)和部门外键
CREATE TABLE IF NOT EXISTS emp (empno INT PRIMARY KEY COMMENT '员工编号',ename VARCHAR(10) NOT NULL COMMENT '员工姓名',job VARCHAR(9) NOT NULL COMMENT '职位',mgr INT COMMENT '直属经理编号(关联自身empno)',hiredate DATE NOT NULL COMMENT '雇佣日期',sal DECIMAL(7,2) NOT NULL COMMENT '月薪',comm DECIMAL(7,2) COMMENT '佣金(仅销售人员有)',deptno INT NOT NULL COMMENT '所属部门编号',-- 外键约束:经理必须是存在的员工(允许顶级领导无经理)CONSTRAINT fk_emp_mgr FOREIGN KEY (mgr) REFERENCES emp(empno),-- 外键约束:部门必须存在CONSTRAINT fk_emp_dept FOREIGN KEY (deptno) REFERENCES dept(deptno)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '员工信息表';-- 创建工资等级表(salgrade)
CREATE TABLE IF NOT EXISTS salgrade (grade INT PRIMARY KEY COMMENT '工资等级(1-6)',losal INT NOT NULL COMMENT '等级最低工资',hisal INT NOT NULL COMMENT '等级最高工资'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '工资等级对照表';-- 创建奖金表(bonus)
CREATE TABLE IF NOT EXISTS bonus (ename VARCHAR(10) NOT NULL COMMENT '员工姓名',job VARCHAR(9) NOT NULL COMMENT '职位',sal DECIMAL(7,2) NOT NULL COMMENT '月薪',comm DECIMAL(7,2) NOT NULL COMMENT '奖金金额',-- 与员工表关联(非严格外键,方便测试)KEY idx_bonus_ename (ename)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '员工奖金表';-- 插入部门数据(6个部门,覆盖不同区域)
INSERT INTO dept (deptno, dname, loc) VALUES
(10, 'ACCOUNTING', 'NEW YORK'),
(20, 'RESEARCH', 'DALLAS'),
(30, 'SALES', 'CHICAGO'),
(40, 'OPERATIONS', 'BOSTON'),
(50, 'MARKETING', 'LOS ANGELES'),
(60, 'SUPPORT', 'SEATTLE');-- 插入员工数据(18条,按“领导→下属”顺序插入,避免外键冲突)
-- 1. 顶级领导(无经理)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000.00, NULL, 10);-- 2. 各部门经理(直属顶级领导)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975.00, NULL, 20),  -- 研发部经理
(7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850.00, NULL, 30),  -- 销售部经理
(7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450.00, NULL, 10),  -- 财务部经理
(7844, 'TURNER', 'MANAGER', 7839, '1981-09-08', 3000.00, NULL, 50), -- 市场部经理
(7900, 'JAMES', 'MANAGER', 7839, '1981-12-03', 2500.00, NULL, 60);  -- 客服部经理-- 3. 研发部(20号部门)员工(经理:JONES 7566)
-- 先插入研发部的次级领导(分析师,可能管理职员)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000.00, NULL, 20),  -- 分析师(可能管理SMITH)
(7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000.00, NULL, 20); -- 分析师(管理ADAMS)-- 再插入研发部的普通职员(直属上述分析师)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800.00, NULL, 20),    -- 职员(经理:FORD 7902)
(7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100.00, NULL, 20);   -- 职员(经理:SCOTT 7788)-- 4. 财务部(10号部门)员工(经理:CLARK 7782)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300.00, NULL, 10);  -- 职员(经理:CLARK 7782)-- 5. 销售部(30号部门)员工(经理:BLAKE 7698)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600.00, 300.00, 30),   -- 销售(经理:BLAKE)
(7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250.00, 500.00, 30),    -- 销售(经理:BLAKE)
(7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250.00, 1400.00, 30), -- 销售(经理:BLAKE)
(7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500.00, 0.00, 30),    -- 销售(经理:BLAKE)
(7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950.00, NULL, 30);         -- 职员(经理:BLAKE)-- 6. 市场部(50号部门)员工(经理:TURNER 7844)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7910, 'FISHER', 'CLERK', 7844, '1982-03-05', 1200.00, NULL, 50),   -- 职员(经理:市场部TURNER)
(7920, 'HUNTER', 'MARKETER', 7844, '1981-11-15', 2200.00, 800.00, 50); -- 市场专员(经理:市场部TURNER)-- 7. 客服部(60号部门)员工(经理:JAMES 7900)
INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES
(7930, 'DAVIS', 'CLERK', 7900, '1982-02-10', 1000.00, NULL, 60),    -- 职员(经理:客服部JAMES)
(7940, 'WILSON', 'SUPPORT', 7900, '1981-08-12', 1800.00, NULL, 60); -- 客服(经理:客服部JAMES)-- 插入工资等级数据(6个等级,覆盖员工工资范围)
INSERT INTO salgrade (grade, losal, hisal) VALUES
(1, 700, 1200),
(2, 1201, 1400),
(3, 1401, 2000),
(4, 2001, 3000),
(5, 3001, 5000),
(6, 5001, 10000);-- 插入奖金数据(8条,含不同职位和金额)
INSERT INTO bonus (ename, job, sal, comm) VALUES
('KING', 'PRESIDENT', 5000.00, 10000.00),  -- 董事长年终奖
('JONES', 'MANAGER', 2975.00, 5000.00),     -- 研发经理奖金
('BLAKE', 'MANAGER', 2850.00, 4500.00),     -- 销售经理奖金
('ALLEN', 'SALESMAN', 1600.00, 1500.00),    -- 销售人员奖金(高于佣金)
('MARTIN', 'SALESMAN', 1250.00, 2000.00),   -- 高佣金销售人员额外奖金
('SCOTT', 'ANALYST', 3000.00, 3500.00),     -- 分析师项目奖金
('HUNTER', 'MARKETER', 2200.00, 1800.00),   -- 市场专员奖金
('WILSON', 'SUPPORT', 1800.00, 800.00);     -- 客服奖金-- 验证数据插入(执行后可查询)
-- SELECT * FROM dept;
-- SELECT empno, ename, job, mgr, deptno FROM emp ORDER BY deptno, mgr, empno;
-- SELECT * FROM salgrade;
-- SELECT * FROM bonus;

2. 多表连接查询

当需要从多个相关表(例如通过外键关联的主表和从表)中获取数据时,需使用连接查询。

本质上就是将两张或多张表合并为一张表进行查询,这里就不得不提到 " 笛卡尔积 "的概念。

2.1 笛卡尔积

2.1.1 什么是笛卡尔积

在 MySQL(或关系数据库)中,笛卡尔积(Cartesian Product) 是指两个或多个表在没有指定关联条件时,所有行之间进行无差别组合的结果。

  • 数学中,两个集合 A 和 B 的笛卡尔积是所有可能的有序对 (a, b) 的集合(其中 a∈A,b∈B)。
  • 在数据库中,若对表 A(行数为 m)和表 B(行数为 n)进行查询时未指定关联条件,则结果集的行数为 m×n,即表 A 的每一行与表 B 的每一行都将组成一条新记录,这就是 “数据库笛卡尔积”。

MySQL数据库中,笛卡尔积的语法如下:

SELECT * FROM 表1, 表2, ...

例如:

mysql> SELECT * FROM student;
+------------+--------+----------+
| student_id | name   | class_id |
+------------+--------+----------+
|          1 | 张三   |        1 |
|          2 | 李四   |        2 |
+------------+--------+----------+
2 rows in set (0.00 sec)mysql> SELECT * FROM class;
+----+------------+
| id | class_name |
+----+------------+
|  1 | 智慧班     |
|  2 | 精品班     |
+----+------------+
2 rows in set (0.00 sec)mysql> SELECT name, class_name FROM student, class;
+--------+------------+
| name   | class_name |
+--------+------------+
| 李四   | 智慧班     |
| 张三   | 智慧班     |
| 李四   | 精品班     |
| 张三   | 精品班     |
+--------+------------+
4 rows in set (0.00 sec)
2.1.2 笛卡尔积的问题

笛卡尔积本身是一种 “机械组合”,但在实际业务中几乎没有意义,因为大部分组合不符合逻辑(比如结果中会出现张三属于精品班的查询结果)。此外,它还会导致:

  • 结果集过大:若表 A 有 1 万行,表 B 有 1 万行,笛卡尔积会产生 1 亿行数据,严重消耗数据库资源(内存、CPU、IO)。
  • 查询效率极低:大量无意义数据的生成和处理会拖慢查询速度,甚至导致数据库卡顿。

在大多数情况当中,我们真正采用的是JOIN关键字来进行多表关联,即" 连接 "。

2.2 内连接

在 MySQL 中,内连接(INNER JOIN) 是最常用的多表连接方式,核心作用是从多个表中筛选出满足关联条件的交集数据,即只返回所有表中 “相互匹配” 的行。

内连接的本质是 “取交集”: 对于参与连接的表 A 和表 B,内连接会根据指定的 “关联条件”(如外键与主键的对应关系),只保留表 A 中与表 B 中匹配的行,不匹配的行(表 A 中无对应表 B 的行,或表 B 中无对应表 A 的行)会被过滤掉。

基本语法:

SELECT 字段列表
FROM 表1
INNER JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
...
-- WHERE子句在JOIN子句之后
  • INNER 关键字可以省略,直接写 JOIN(默认就是内连接);
  • 多个表连接时,可连续使用 INNER JOIN 关联,每个连接都需要一个 ON 子句指定关联条件;
  • 表名也可取别名,方便再关联条件处引用。

示例:

mysql> SELECT name, class_name FROM student s JOIN class c ON s.class_id = c.id;
+--------+------------+
| name   | class_name |
+--------+------------+
| 张三   | 智慧班     |
| 李四   | 精品班     |
+--------+------------+
2 rows in set (0.00 sec)

显示各个员工的名字和及其部门名称:

mysql> SELECT ename, dname FROM emp JOIN dept ON emp.deptno = dept.deptno;
+--------+------------+
| ename  | dname      |
+--------+------------+
| CLARK  | ACCOUNTING |
| KING   | ACCOUNTING |
| MILLER | ACCOUNTING |
| SMITH  | RESEARCH   |
| JONES  | RESEARCH   |
| SCOTT  | RESEARCH   |
| ADAMS  | RESEARCH   |
| FORD   | RESEARCH   |
| BLAKE  | SALES      |
| TURNER | MARKETING  |
| FISHER | MARKETING  |
| HUNTER | MARKETING  |
| JAMES  | SUPPORT    |
| DAVIS  | SUPPORT    |
| WILSON | SUPPORT    |
+--------+------------+
15 rows in set (0.00 sec)

2.3 外连接

在 MySQL 中,外连接(Outer Join) 与内连接的核心区别是:外连接会保留 “主表” 的所有行,即使 “从表” 中没有匹配的记录(不匹配的部分用NULL填充)。

  • 主表:需要被完整保留所有行的表(左外连接中是左表,右外连接中是右表)。
  • 从表:与主表关联的表,若没有匹配的行,对应字段用NULL填充。

外连接主要分为左外连接(LEFT JOIN) 和右外连接(RIGHT JOIN),用于需要完整保留某张表数据的场景。

2.3.1 左外连接

左外连接以左表为主表,会返回左表的所有行,以及右表中与左表满足关联条件的行;若右表无匹配,右表字段显示NULL。

基本语法:

SELECT 字段列表
FROM 左表  -- 主表:所有行都会被保留
LEFT [OUTER] JOIN 右表  -- 从表:只返回匹配的行,不匹配则为NULL
ON 左表.关联字段 = 右表.关联字段;  -- 关联条件
2.3.2 右外连接

右外连接以右表为主表,会返回右表的所有行,以及左表中与右表满足关联条件的行;若左表无匹配,左表字段显示NULL。

基本语法:

SELECT 字段列表
FROM 左表  -- 从表:只返回匹配的行,不匹配则为NULL
RIGHT [OUTER] JOIN 右表  -- 主表:所有行都会被保留
ON 左表.关联字段 = 右表.关联字段;  -- 关联条件
2.3.3 示例

我们注意到40号部门是没有员工的:

mysql> SELECT * FROM emp;
+-------+--------+-----------+------+------------+---------+--------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal     | comm   | deptno |
+-------+--------+-----------+------+------------+---------+--------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |   NULL |     20 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |   NULL |     20 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |   NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |   NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |   NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |   NULL |     10 |
|  7844 | TURNER | MANAGER   | 7839 | 1981-09-08 | 3000.00 |   NULL |     50 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |   NULL |     20 |
|  7900 | JAMES  | MANAGER   | 7839 | 1981-12-03 | 2500.00 |   NULL |     60 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |   NULL |     20 |
|  7910 | FISHER | CLERK     | 7844 | 1982-03-05 | 1200.00 |   NULL |     50 |
|  7920 | HUNTER | MARKETER  | 7844 | 1981-11-15 | 2200.00 | 800.00 |     50 |
|  7930 | DAVIS  | CLERK     | 7900 | 1982-02-10 | 1000.00 |   NULL |     60 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |   NULL |     10 |
|  7940 | WILSON | SUPPORT   | 7900 | 1981-08-12 | 1800.00 |   NULL |     60 |
+-------+--------+-----------+------+------------+---------+--------+--------+
15 rows in set (0.00 sec)mysql> SELECT * FROM dept;
+--------+------------+-------------+
| deptno | dname      | loc         |
+--------+------------+-------------+
|     10 | ACCOUNTING | NEW YORK    |
|     20 | RESEARCH   | DALLAS      |
|     30 | SALES      | CHICAGO     |
|     40 | OPERATIONS | BOSTON      |
|     50 | MARKETING  | LOS ANGELES |
|     60 | SUPPORT    | SEATTLE     |
+--------+------------+-------------+
6 rows in set (0.01 sec)

当我们查询各个部门属下有哪些员工时:

-- 内连接
mysql> SELECT dept.deptno, ename FROM dept JOIN emp ON dept.deptno = emp.deptno ORDER BY deptno ASC;
+--------+--------+
| deptno | ename  |
+--------+--------+
|     10 | CLARK  |
|     10 | KING   |
|     10 | MILLER |
|     20 | SMITH  |
|     20 | JONES  |
|     20 | SCOTT  |
|     20 | ADAMS  |
|     20 | FORD   |
|     30 | BLAKE  |
|     50 | TURNER |
|     50 | FISHER |
|     50 | HUNTER |
|     60 | JAMES  |
|     60 | DAVIS  |
|     60 | WILSON |
+--------+--------+
15 rows in set (0.00 sec)-- 左外连接
mysql> SELECT dept.deptno, ename FROM dept LEFT JOIN emp ON dept.deptno = emp.deptno ORDER BY deptno ASC;
+--------+--------+
| deptno | ename  |
+--------+--------+
|     10 | CLARK  |
|     10 | KING   |
|     10 | MILLER |
|     20 | SMITH  |
|     20 | JONES  |
|     20 | SCOTT  |
|     20 | ADAMS  |
|     20 | FORD   |
|     30 | BLAKE  |
|     40 | NULL   |
|     50 | TURNER |
|     50 | FISHER |
|     50 | HUNTER |
|     60 | JAMES  |
|     60 | DAVIS  |
|     60 | WILSON |
+--------+--------+
16 rows in set (0.00 sec)-- 右外连接
mysql> SELECT dept.deptno, ename FROM emp RIGHT JOIN dept ON dept.deptno = emp.deptno ORDER BY deptno ASC;
+--------+--------+
| deptno | ename  |
+--------+--------+
|     10 | CLARK  |
|     10 | KING   |
|     10 | MILLER |
|     20 | SMITH  |
|     20 | JONES  |
|     20 | SCOTT  |
|     20 | ADAMS  |
|     20 | FORD   |
|     30 | BLAKE  |
|     40 | NULL   |
|     50 | TURNER |
|     50 | FISHER |
|     50 | HUNTER |
|     60 | JAMES  |
|     60 | DAVIS  |
|     60 | WILSON |
+--------+--------+
16 rows in set (0.00 sec)

2.4 合并查询

在 MySQL 中,UNIONUNION ALL都是用于合并多个SELECT查询的结果集的关键字,它们的核心作用是将多个独立查询的结果 “拼接” 成一个整体。其中UNION会对合并结果进行去重,而UNION ALL不会。

基本语法:

-- UNION:合并并去重
SELECT 列1, 列2, ... FROM 表1 WHERE 条件
UNION
SELECT 列1, 列2, ... FROM 表2 WHERE 条件;-- UNION ALL:合并但不去重
SELECT 列1, 列2, ... FROM 表1 WHERE 条件
UNION ALL
SELECT 列1, 列2, ... FROM 表2 WHERE 条件;

使用UNION或UNION ALL时,需满足以下前提

  • 每个SELECT语句查询的列数必须相同;
  • 对应位置的列数据类型必须兼容(如INT与DECIMAL兼容,VARCHAR与TEXT兼容);
  • 列的顺序需一致(否则结果的列含义可能混乱)。
mysql> SELECT * FROM bonus-> UNION-> SELECT * FROM bonus;
+--------+-----------+---------+----------+
| ename  | job       | sal     | comm     |
+--------+-----------+---------+----------+
| KING   | PRESIDENT | 5000.00 | 10000.00 |
| JONES  | MANAGER   | 2975.00 |  5000.00 |
| BLAKE  | MANAGER   | 2850.00 |  4500.00 |
| ALLEN  | SALESMAN  | 1600.00 |  1500.00 |
| MARTIN | SALESMAN  | 1250.00 |  2000.00 |
| SCOTT  | ANALYST   | 3000.00 |  3500.00 |
| HUNTER | MARKETER  | 2200.00 |  1800.00 |
| WILSON | SUPPORT   | 1800.00 |   800.00 |
+--------+-----------+---------+----------+
8 rows in set (0.00 sec)mysql> SELECT * FROM bonus-> UNION ALL-> SELECT * FROM bonus;
+--------+-----------+---------+----------+
| ename  | job       | sal     | comm     |
+--------+-----------+---------+----------+
| KING   | PRESIDENT | 5000.00 | 10000.00 |
| JONES  | MANAGER   | 2975.00 |  5000.00 |
| BLAKE  | MANAGER   | 2850.00 |  4500.00 |
| ALLEN  | SALESMAN  | 1600.00 |  1500.00 |
| MARTIN | SALESMAN  | 1250.00 |  2000.00 |
| SCOTT  | ANALYST   | 3000.00 |  3500.00 |
| HUNTER | MARKETER  | 2200.00 |  1800.00 |
| WILSON | SUPPORT   | 1800.00 |   800.00 |
| KING   | PRESIDENT | 5000.00 | 10000.00 |
| JONES  | MANAGER   | 2975.00 |  5000.00 |
| BLAKE  | MANAGER   | 2850.00 |  4500.00 |
| ALLEN  | SALESMAN  | 1600.00 |  1500.00 |
| MARTIN | SALESMAN  | 1250.00 |  2000.00 |
| SCOTT  | ANALYST   | 3000.00 |  3500.00 |
| HUNTER | MARKETER  | 2200.00 |  1800.00 |
| WILSON | SUPPORT   | 1800.00 |   800.00 |
+--------+-----------+---------+----------+
16 rows in set (0.00 sec)

2.5 全外连接

全外连接的逻辑是:保留左表和右表的所有行,匹配的行合并,不匹配的部分用NULL填充。

但MySQL 不直接支持FULL JOIN,需通过 LEFT JOIN + UNION + RIGHT JOIN 组合实现(UNION用于合并两个结果集)。

3. 子查询

在 MySQL 中,子查询(Subquery) 是指嵌套在另一个查询(称为 “主查询”)中的查询语句。子查询的结果通常用于辅助主查询过滤数据、计算值或作为临时数据源,从而实现更复杂的查询逻辑。

3.1 子查询在WHERE子句中

3.1.1 单行子查询(返回 1 行 1 列)

子查询结果为单个值,主查询中可使用=、>、<、>=、<=等比较运算符。

SELECT 若干列 
FROM 表1 
WHERE 某列 oper (SELECT 对应列 FROM 表2 WHERE 条件表达式);

示例:查询与KING同一部门的员工

mysql> SELECT ename FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'KING');
+--------+
| ename  |
+--------+
| CLARK  |
| KING   |
| MILLER |
+--------+
3 rows in set (0.00 sec)
3.1.2 多行子查询(返回多行 1 列)

子查询结果为多个值,主查询中需使用IN、NOT IN、ANY、ALL等多行运算符。

  • IN:判断值是否在子查询结果中(等价于 “等于其中任意一个”)。
    示例:查询岗位在10号部门的工作岗位中的雇员的名字,岗位,工资,部门号
    mysql> SELECT ename, job, sal, deptno FROM emp WHERE 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 |
    | CLARK  | MANAGER   | 2450.00 |     10 |
    | KING   | PRESIDENT | 5000.00 |     10 |
    | TURNER | MANAGER   | 3000.00 |     50 |
    | ADAMS  | CLERK     | 1100.00 |     20 |
    | JAMES  | MANAGER   | 2500.00 |     60 |
    | FISHER | CLERK     | 1200.00 |     50 |
    | DAVIS  | CLERK     | 1000.00 |     60 |
    | MILLER | CLERK     | 1300.00 |     10 |
    +--------+-----------+---------+--------+
    11 rows in set (0.00 sec)
  • ANY/SOME:与比较运算符配合,判断值是否满足 “与子查询结果中的任意一个比较成立”。
    示例:查询工资比部门50的任意员工的工资高的员工的姓名、工资和部门号(不包括部门50)
    mysql> SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 50) AND deptno != 50;
    +--------+---------+--------+
    | ename  | sal     | deptno |
    +--------+---------+--------+
    | JONES  | 2975.00 |     20 |
    | BLAKE  | 2850.00 |     30 |
    | CLARK  | 2450.00 |     10 |
    | SCOTT  | 3000.00 |     20 |
    | KING   | 5000.00 |     10 |
    | JAMES  | 2500.00 |     60 |
    | FORD   | 3000.00 |     20 |
    | MILLER | 1300.00 |     10 |
    | WILSON | 1800.00 |     60 |
    +--------+---------+--------+
    9 rows in set (0.00 sec)
  • ALL:与比较运算符配合,判断值是否满足 “与子查询结果中的所有值比较都成立”。
    示例:显示工资比部门50的所有员工的工资高的员工的姓名、工资和部门号
    mysql> SELECT ename, sal, deptno FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno = 50);
    +-------+---------+--------+
    | ename | sal     | deptno |
    +-------+---------+--------+
    | KING  | 5000.00 |     10 |
    +-------+---------+--------+
    1 row in set (0.00 sec)
3.1.3 多列子查询(返回若干行多列)
SELECT 若干列 
FROM 表1 
WHERE (列1, 列2, ...) oper (SELECT 对应列 FROM 表2 WHERE 条件表达式);

这里oper只能是等或者不等。

示例:查询和SMITH职位和部门完全相同的员工姓名

mysql> SELECT ename FROM emp WHERE (job, deptno) = (SELECT job, deptno FROM emp WHERE ename = 'SMITH') AND ename != 'SMITH';
+-------+
| ename |
+-------+
| ADAMS |
+-------+
1 row in set (0.00 sec)

3.2 EXISTS子查询(判断是否存在结果)

EXISTS不关心子查询的具体结果,只判断子查询是否返回至少一行数据:

  • 若子查询有结果,EXISTS返回TRUE,主查询保留当前行;
  • 若子查询无结果,EXISTS返回FALSE,主查询过滤当前行。

示例:查询有员工的部门

mysql> SELECT * FROM dept WHERE EXISTS (SELECT * FROM emp WHERE deptno = dept.deptno);
+--------+------------+-------------+
| deptno | dname      | loc         |
+--------+------------+-------------+
|     10 | ACCOUNTING | NEW YORK    |
|     20 | RESEARCH   | DALLAS      |
|     30 | SALES      | CHICAGO     |
|     50 | MARKETING  | LOS ANGELES |
|     60 | SUPPORT    | SEATTLE     |
+--------+------------+-------------+
5 rows in set (0.00 sec)

NOT EXISTS则相反,用于筛选 “子查询无结果” 的行。

3.3 子查询在FROM子句中

子查询的结果作为一个 “临时表”(需指定别名),主查询从该临时表中查询数据。这种子查询也称为 “派生表”。

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

mysql> SELECT ename, emp.deptno, sal, tmp.avgSal FROM emp JOIN (SELECT deptno, AVG(sal) avgSal FROM emp GROUP BY deptno) tmp ON emp.deptno = tmp
.deptno WHERE sal > tmp.avgSal;
+--------+--------+---------+-------------+
| ename  | deptno | sal     | avgSal      |
+--------+--------+---------+-------------+
| JONES  |     20 | 2975.00 | 2175.000000 |
| SCOTT  |     20 | 3000.00 | 2175.000000 |
| KING   |     10 | 5000.00 | 2916.666667 |
| TURNER |     50 | 3000.00 | 2133.333333 |
| JAMES  |     60 | 2500.00 | 1766.666667 |
| FORD   |     20 | 3000.00 | 2175.000000 |
| HUNTER |     50 | 2200.00 | 2133.333333 |
| WILSON |     60 | 1800.00 | 1766.666667 |
+--------+--------+---------+-------------+
8 rows in set (0.00 sec)

3.4 子查询在SELECT子句中

子查询返回单行单列(标量),作为主查询结果集中的一个列值(通常用于计算或补充信息)。

示例:查询各个员工的名称与其所属部门的名称

mysql> SELECT ename, (SELECT dname FROM dept WHERE dept.deptno = emp.deptno) AS '部门' FROM emp;
+--------+------------+
| ename  | 部门       |
+--------+------------+
| SMITH  | RESEARCH   |
| JONES  | RESEARCH   |
| BLAKE  | SALES      |
| CLARK  | ACCOUNTING |
| SCOTT  | RESEARCH   |
| KING   | ACCOUNTING |
| TURNER | MARKETING  |
| ADAMS  | RESEARCH   |
| JAMES  | SUPPORT    |
| FORD   | RESEARCH   |
| FISHER | MARKETING  |
| HUNTER | MARKETING  |
| DAVIS  | SUPPORT    |
| MILLER | ACCOUNTING |
| WILSON | SUPPORT    |
+--------+------------+
15 rows in set (0.00 sec)

3.5 相关子查询与非相关子查询

  • 非相关子查询:子查询可独立执行,不依赖主查询的字段(执行一次后将结果传递给主查询)。例如:WHERE class_id IN (SELECT id FROM classes)。
  • 相关子查询:子查询依赖主查询的字段,主查询每执行一行,子查询就会重新执行一次(子查询与主查询通过字段关联)。

例如,3.1当中使用的都是非相关子查询,而3.2~3.4使用的都是相关子查询。

http://www.dtcms.com/a/442965.html

相关文章:

  • wordpress 手机网站支付宝360全景图制作
  • 计算机如何生成随机数? 什么是种子?
  • Qemu调试ARM64 linux内核 IOMMU(SMMU)驱动环境搭建
  • 正版宝安网站推广建设电子商务网站市场分析
  • Qt可执行文件打包全流程
  • 大庆免费网站建设公司网站开发平台是什么
  • 做网站用什么空间网络班级网站建设
  • UE5 小知识点 —— 10 - 鼠标操作
  • 西安英文网站建设安丘网站建设报价
  • llama.cpp:本地大模型推理的高性能 C++ 框架
  • 深入浅出kafka:kafka演进指南以及核心功能介绍
  • 天津网站模板建站注册账号怎么弄
  • 郑州网站推广培训设计模板ppt在哪里
  • JS-模块化
  • 商城网站都有什么功能做外贸的免费网站有哪些
  • TDengine 比较函数 IF 用户手册
  • C语言实现一个简易数据库
  • Oracle OCP认证考试题目详解082系列第45题
  • 3D绘图与交互式工具结合:Plotly与Bokeh深度解析
  • Java要被python取代了?3个技术维度拆分分析
  • 【软考-分析】
  • 站群软件想在网上卖货需要怎么做
  • 水果成篮_优选算法(C++)滑动窗口
  • dw网站建设字体颜色做超市dm的网站
  • 网站seo查询工具wordpress小工具页脚
  • PostIn入门到实战(7) - 如何快速调试websocket接口
  • 网站建设需求公司内部调查福田深圳网站建设
  • 如果自己建立网站做甲方去哪个网站应聘
  • 重要数据、长期存储 | 为什么要用机械硬盘?
  • 做木业网站怎样起名电商平台推广员是做什么的