多表查询

1. 多表关系

在设计数据库时,表与表之间常见的关系有三种:

|---------|-----------|--------------------|
| 关系 | 示例 | 实现方式 |
| 一对多 | 部门 → 员工 | 在多的一方建外键 → 一的一方主键 |
| 多对多 | 学生 ↔ 课程 | 建中间表,含两个外键分别指向两表主键 |
| 一对一 | 用户 ↔ 用户详情 | 任一方加外键并设 UNIQUE 约束 |

实战要点 :中间表通常用联合主键 PRIMARY KEY(student_id, course_id)。


2. 内连接(INNER JOIN)

内连接查询两表的交集部分。

2.1 隐式内连接

复制代码
SELECT 字段 FROM 表1, 表2 WHERE 条件;

2.2 显式内连接(推荐)

复制代码
SELECT 字段 FROM 表1 [INNER] JOIN 表2 ON 条件;

为什么推荐显式? 1. 语义更清晰 2. 优化器更容易识别 3. 标准 SQL,跨数据库兼容

复制代码
-- 示例:查询员工姓名及所属部门名称
select e.name, d.name from employee e inner join dept d on e.dept = d.id;

3. 外连接(OUTER JOIN)

3.1 左外连接

查询左表全部数据 + 两表交集。

复制代码
SELECT 字段 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件;

3.2 右外连接

查询右表全部数据 + 两表交集。

复制代码
SELECT 字段 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 条件;

实践建议:日常开发以左外连接为主,右外连接可改写为左外(交换表顺序即可)。

3.3 内连接 vs 外连接

|-----|------------|----------------|
| 类型 | 返回 | 场景 |
| 内连接 | 两表匹配行 | 查有关联的数据 |
| 外连接 | 主表全部 + 匹配行 | 查"所有"数据(含无关联的) |


4. 自连接

表与自身进行连接。必须使用别名区分。

复制代码
-- 查询员工及其直属领导的姓名
select a.name '员工', b.name '领导'
from employee a left join employee b on a.manager = b.id;

典型场景:组织架构(上级下级)、分类树(父子分类)、评论回复等。


5. 联合查询(UNION)

将多条查询结果合并为一条结果集。

复制代码
SELECT ... FROM 表A
UNION [ALL]
SELECT ... FROM 表B;

|-----------|---------------|
| 关键字 | 说明 |
| UNION | 去重(额外排序,性能略低) |
| UNION ALL | 不去重(性能更高) |

联合查询 vs OR:UNION 不会导致索引失效,OR 一侧无索引则全索引失效。

UNION 使用条件:

  • 多个 SELECT 的列数必须一致
  • 对应列的数据类型必须兼容

6. 子查询

嵌套在 SQL 语句中的 SELECT 语句,外部可以是 INSERT / UPDATE / DELETE / SELECT。

6.1 按结果分类

|-----------|-----------|------------------|----------------|
| 分类 | 返回结果 | 常用操作符 | 示例 |
| 标量子查询 | 单个值(一行一列) | =、<>、>、< | 查销售部所有员工 |
| 列子查询 | 一列多行 | IN、ANY、ALL | 查销售部和市场部员工 |
| 行子查询 | 一行多列 | =、IN | 查与某人薪资和领导相同的员工 |
| 表子查询 | 多行多列 | IN、FROM 后 | 在 FROM 后作为临时表 |

6.2 列子查询操作符详解

|------------|-------------------------|
| 操作符 | 说明 |
| IN | 在集合中 |
| ANY / SOME | 满足任一即可(> ANY → 大于最小值) |
| ALL | 必须满足全部(> ALL → 大于最大值) |

6.3 实战示例

复制代码
-- 标量子查询:查询销售部所有员工
select * from employee where dept = (select id from dept where name='销售部');

-- 列子查询:查询销售部和市场部员工
select * from employee where dept in (select id from dept where name in ('销售部','市场部'));

-- 行子查询:查询与 "张三" 薪资和直属领导相同的员工
select * from employee where (salary, manager) = (select salary, manager from employee where name='张三');

-- 表子查询:查询 2006 年后入职员工及部门(子查询作为临时表)
select e.*, d.* from (select * from employee where entrydate>'2006-01-01') e
left join dept d on e.dept = d.id;
相关推荐
不爱学英文的码字机器1 小时前
从Q1迁到T1,同一个编号已经换了含义
前端·数据库·microsoft
Lynne3091 小时前
TSN 技术解析:如何应对工业网络中的延迟、抖动与丢包?
数据库·确定性通信·tsn时间敏感网络
2601_957084841 小时前
2026年工贸一体服装供应链SCM系统丨多品牌多工厂管控的架构设计:主数据分层、考核口径三要素与共享隔离模型
数据库·scm·服装供应链系统·服装scm·服装供应链
Aloudata1 小时前
语义资产运营指南:如何管理指标、维度、口径、Owner、血缘和使用记录
数据库·人工智能·数据分析·数据资产·dataagent·语义层
PaperData1 小时前
2006-2024年地级市能源消费强度数据
数据库·能源
龙亘川2 小时前
城市公共安全治理如何从“人海战术“走向“数据驱动“?
大数据·数据库·人工智能·安全·microsoft·智慧城市·数据可视化
betazhou2 小时前
Apache Seatunnel 抽取SQL server实时同步到Oracle-多表同步(五)
数据库·oracle·sqlserver·apache·seatunnel
神也畏惧菠萝2 小时前
Coze 工作流数据库 Day06:架构与高级循环控制的深度技术分析
数据库·架构·llm·coze·coze数据库·数据库流程结构
麦壳饼2 小时前
SonnetDB:空间函数别名的参数与兼容边界
数据库·sonnetdb