7. 多表查询
这是什么:JOIN = 把两张表按某个共同字段拼在一起查询的写法;外键 = 表里存的「指向另一张表某行的 id」。
为什么用:真实数据从来不止一张表:文章是文章,用户是用户。「这篇文章是谁写的」这种问题,单表根本查不出来,必须把两表连起来。
如何用:本章先用 user_id 外键把用户表和文章表系上,再练 INNER JOIN 与 LEFT JOIN 的区别。
7.1 外键:把两张表系在一起
规则:在"多"的那一方,存"一"方的 id。建一张文章表带作者外键:
CREATE TABLE `article` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(120) NOT NULL,
`views` INT DEFAULT 0,
`user_id` INT NOT NULL, -- 作者是谁:存用户的 id
PRIMARY KEY (`id`)
);
INSERT INTO `article` (`title`, `views`, `user_id`) VALUES
('我的第一篇博客', 58, 1),
('CSS 妙用', 90, 1),
('新手如何学前端', 12, 2);
user_id = 1 就指查 user 表里 id = 1(frog)——存单行还是存双表?存 id,用的时候 JOIN。
关系分类:一对多(一个用户写多篇文章,如上)、多对多(标签 ↔ 文章,需中间表,后面进阶)、一对一(拆表用)。
7.2 JOIN:按条件拼表
SELECT a.`title`, a.`views`, u.`username`
FROM `article` a
JOIN `user` u ON a.`user_id` = u.`id`;
你会看到:
+------------------+-------+----------+
| title | views | username |
+------------------+-------+----------+
| 我的第一篇博客 | 58 | frog |
| CSS 妙用 | 90 | frog |
| 新手如何学前端 | 12 | panda |
+------------------+-------+----------+
| 片段 | 作用 |
|---|---|
FROM article a |
给表起短别名 |
JOIN user u |
另一张表也起别名 |
ON a.user_id = u.id |
两行怎么算「配对」(这行是核心) |
7.3 INNER JOIN 与 LEFT JOIN
| 写法 | 规则 |
|---|---|
JOIN(即 INNER JOIN) |
两边都能配上才返回 |
LEFT JOIN |
以左表为准,右表配不上用 NULL 补位 |
-- 查每个用户有几篇文章:用 LEFT JOIN,用户没文章也显示 0
SELECT u.`username`, COUNT(a.`id`) AS `cnt`
FROM `user` u
LEFT JOIN `article` a ON a.`user_id` = u.`id`
GROUP BY u.`id`, u.`username`;
你会看到:没写文章的用户也有记录,cnt 是 0(INNER JOIN 会把他弄丢)。
口诀:统计"每个用户都算"用 LEFT JOIN,只看配上父母的用 INNER JOIN。
7.4 JOIN 后的 SELECT 套路
JOIN 以来前面学的全用上了:
SELECT u.`username`, a.`title`, a.`views`
FROM `article` a
JOIN `user` u ON a.`user_id` = u.`id`
WHERE a.`views` > 50 -- 行筛
ORDER BY a.`views` DESC -- 排序
LIMIT 10;
7.5 动手改
- JOIN 查「每篇文章的作者名」,按阅读量倒序
- 给某个用户加一篇文章后,重跑 LEFT JOIN 统计
- 故意插入一条
user_id = 99的文章,对比 INNER / LEFT 结果
7.6 小结
- 外键:多方存一方的 id,配对靠
ON a.xx = b.id - INNER JOIN 只出配对成功的;LEFT JOIN 保左表完整
- JOIN 常和前面学的 WHERE / GROUP BY / ORDER BY 套用
下一章:综合练习:博客数据表 🐸