
本文介绍如何使用 sql 的 left join 实现三级关联查询,从 blog、category 和 assigned 表中完整提取每篇博客的标题、描述、发布时间等基础信息,并同时获取其直接分类(category)及可为空的子分类(subcategory)名称。
本文介绍如何使用 sql 的 left join 实现三级关联查询,从 blog、category 和 assigned 表中完整提取每篇博客的标题、描述、发布时间等基础信息,并同时获取其直接分类(category)及可为空的子分类(subcategory)名称。
在实际博客系统中,分类结构常呈现层级关系:一个博客属于某个主分类(如“Front End Development”),而该主分类又可能隶属于更上层的子分类(如“JavaScript”是“Front End Development”的子类)。你的数据库设计中,category 表通过 idsub 字段指向自身(自关联),形成树状结构;assigned 表则承担博客与分类之间的多对多桥梁角色。
要一次性查出博客 + 主分类名 + 子分类名(允许为 NULL),关键在于正确处理自关联与外键缺失场景。此时必须使用 LEFT JOIN,而非旧式逗号连接或 INNER JOIN,否则会丢失未分配分类的博客,或无法展示 idsub 为空的分类所对应的 NULL 子分类。
以下是推荐的标准化查询语句:
SELECT b.idblog, b.title, b.description, b.date, c.categoryname AS categoryname, sc.categoryname AS subcategoryname FROM blog b LEFT JOIN assigned a ON b.idblog = a.idblog LEFT JOIN category c ON a.idcategory = c.idcategory LEFT JOIN category sc ON c.idsub = sc.idcategory WHERE c.categoryname LIKE 'Front End Development';
✅ 关键说明:
-
LEFT JOIN assigned确保即使某博客尚未分配任何分类,仍会被保留(此时c.*和sc.*字段为 NULL); - 第二个
LEFT JOIN category c关联主分类,获取categoryname; - 第三个
LEFT JOIN category sc是自关联:将c.idsub作为外键,再次连接category表本身,从而取出子分类名称;因idsub允许为 NULL,LEFT JOIN保证子分类字段安全返回 NULL 而非被过滤掉; - 别名(
b,a,c,sc)提升可读性与书写效率; -
WHERE子句放在最后,仅用于筛选主分类条件——切勿在ON中添加categoryname LIKE ...,否则可能意外改变LEFT JOIN的语义(导致 NULL 行被排除)。
⚠️ 注意事项:
- 若需查询所有博客(不限定分类),请直接移除
WHERE子句; - 确保
category.idsub字段定义为INT NULL或对应类型,并建立索引(如INDEX idx_idsub (idsub))以提升自关联性能; - 在 MySQL 5.7+ 或 PostgreSQL 中,该写法完全兼容;若使用 SQLite,需确认其支持表别名的多次引用;
- 避免使用过时的隐式连接(
FROM blog, assigned, category WHERE ...),它难以维护、易出错,且无法正确表达外连接逻辑。
掌握这种多级 LEFT JOIN 模式,不仅能解决当前的博客分类查询需求,也为处理标签体系、组织架构、产品类目树等典型层级数据提供了通用范式。










