创建时间: 2026-09-01最后更新: 2026-09-01

1. 关联查询

关系型数据库把不同类型的数据放在不同表中。任务只保存 project_id,项目只保存 owner_id,不会在每条任务中重复项目名称和用户邮箱。

当接口需要同时返回任务、项目和负责人信息时,就要根据这些字段之间的关系重新组合表中的行。SQL 使用 JOIN 表达这种关联。

JOIN 本身并不要求数据库已经定义外键,它只按照连接条件判断两行是否匹配。外键的职责是保证 tasks.project_id、projects.owner_id 等引用值确实存在,从而让这些连接关系长期保持可靠。

现有关系如下:

current-relations.txt
1
projects.owner_id -> users.id
2
tasks.project_id -> projects.id

常见连接类型如下:

类型返回哪些行
INNER JOIN只返回左右两侧能够匹配的行
LEFT JOIN返回左侧全部行,右侧没有匹配时用 NULL 补齐
RIGHT JOIN返回右侧全部行,左侧没有匹配时用 NULL 补齐
FULL JOIN返回两侧全部行,任意一侧没有匹配时用 NULL 补齐
CROSS JOIN返回左右两侧行的所有组合,也就是笛卡尔积

实际业务最常使用 INNER JOIN 和 LEFT JOIN,本文也会重点讲解这两种连接,最后再说明 CROSS JOIN 的用途和风险。

读取任务及其项目名称:

task-projects.sql
1
SELECT
2
tasks.id,
3
tasks.title,
4
projects.name AS project_name
5
FROM tasks
6
JOIN projects ON projects.id = tasks.project_id;

ON 后面的条件说明两张表的行如何匹配。对于每条任务,数据库找到 projects.id 与 tasks.project_id 相等的项目,再把需要的列放进同一结果行。

这里的 JOIN 默认等同于 INNER JOIN,只返回两边都能匹配的行。由于任务外键要求项目存在,正常数据都能找到对应项目。连接只会产生本次查询使用的结果集,不会把三张表合并存储,也不会修改原表。

2. 表与列别名

多表查询中经常出现同名列,因此应该给表设置简短且能辨认的别名:

join-aliases.sql
01
SELECT
02
t.id AS task_id,
03
t.title AS task_title,
04
t.status,
05
p.id AS project_id,
06
p.name AS project_name,
07
u.id AS owner_id,
08
u.display_name AS owner_name
09
FROM tasks AS t
10
JOIN projects AS p ON p.id = t.project_id
11
JOIN users AS u ON u.id = p.owner_id
12
WHERE t.archived_at IS NULL
13
ORDER BY t.created_at DESC, t.id DESC;

别名只在当前 SQL 中有效,不会修改真实表名。为表指定别名后,同一层查询应该通过别名引用它,例如写了 FROM tasks AS t 后就继续使用 t.id,而不是 tasks.id。t、p、u 适合短查询;查询很复杂时,也可以使用 task、project、owner 等更有意义的别名。

限定列名前缀不仅用于解决歧义,也能说明数据来源。看到 u.display_name,读者不必回到表结构中猜测名称来自哪张表。

正在验证登录状态
请稍候,验证完成后将继续显示文章内容