外观
什么是关联查询
关联查询(Join Query)在SQL中是指将两个或多个表中的数据行根据某些共同的列进行组合,以形成一个新的结果集。 这种查询允许你从多个表中检索信息,而这些表通常通过某种逻辑关系相连,比如主键-外键关系。关联查询是关系型数据库管理系统(RDBMS)中用于处理和分析跨多表数据的核心功能之一。
- 基于条件组合数据: 关联查询使用一个或多个条件来决定哪些行应该被组合在一起。这个条件通常是两个表中某一列值相等,但这并不限于等于操作,也可以是其他类型的比较或逻辑表达式。
- 创建临时结果集: 当执行关联查询时,数据库会创建一个临时的结果集,它包含了来自参与关联的所有表的相关数据。这个结果集可以进一步被过滤、排序或分组。
- 多种连接类型: SQL支持不同的JOIN类型,如INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN等,每种类型决定了当没有匹配的行时如何处理结果集。例如,INNER JOIN只会返回有匹配的数据行,而LEFT JOIN会保留左表的所有行,即使右表中没有匹配项。
- 提高数据检索效率: 通过正确地使用索引和优化JOIN条件,关联查询可以帮助提高数据检索的速度和效率。这是因为在实际应用中,数据往往分散存储在多个表中,有效地关联这些表能够减少数据冗余并提高查询性能。
- 遵循关系模型原则: 关联查询的设计和实现紧密遵循关系数据库理论中的规范化原则,确保数据的一致性和完整性。同时,它也体现了关系型数据库的一个重要特性:能够在保持数据独立性的同时,灵活地访问和操作数据。
直接实操,演示用的数据库和表:
数据库名称为: project_test
表 course:
bash
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | YES | | NULL | |
| outline | varchar(255) | YES | | NULL | |
| hour | varchar(10) | NO | | 0 | |
| classroom | varchar(255) | YES | | NULL | |
| remark | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
数据
bash
+----+--------------------+--------------------------+------+--------------------------------+-----------------+
| id | title | outline | hour | classroom | remark |
+----+--------------------+--------------------------+------+--------------------------------+-----------------+
| 1 | 高数 | 简介12332 | 100 | 阶梯教室201 | 备注 |
| 2 | c语言 | c语言设计 | 70 | 大课堂8811 | 自带机器 |
| 3 | 程控交换技术 | 程控交换技术简介 | 100 | 通讯工程学院实验室203 | 不会的别来 |
| 4 | c语言进阶 | c语言程序进阶 | 50 | 大课堂8811 | 备注 |
| 5 | 光通信 | 阿巴阿巴 | 80 | 通讯工程学院实验室206 | 阿巴 |
| 6 | 水课 | 来划水 | 20 | 宿舍 | 水课啊 |
+----+--------------------+--------------------------+------+--------------------------------+-----------------+
teacher
bash
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| tel | varchar(255) | YES | | NULL | |
| title | varchar(255) | YES | | NULL | |
| teacher_id | int(11) | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
bash
+----+-----------+------+-----------------------+------------+
| id | name | tel | title | teacher_id |
+----+-----------+------+-----------------------+------------+
| 1 | 张老师 | 101 | 博士生导师 | 101 |
| 2 | 李老师 | 102 | 研究生导师 | 102 |
| 3 | 白老师 | 103 | 科学院院士 | 103 |
| 4 | 华老师 | 104 | 诺贝尔奖获得者 | 104 |
+----+-----------+------+-----------------------+------------+
student
bash
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| student_id | varchar(200) | NO | | NULL | |
| sex | varchar(255) | NO | | NULL | |
| profession | varchar(255) | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
bash
+----+--------+------------+-----+--------------------------+
| id | name | student_id | sex | profession |
+----+--------+------------+-----+--------------------------+
| 1 | 张三 | s001 | 男 | 通信工程 |
| 2 | 李四 | s002 | 男 | 通信工程 |
| 3 | 王五 | s003 | 男 | 通信工程 |
| 4 | 刘六 | s004 | 女 | 通信工程 |
| 5 | 毛七 | s005 | 女 | 通信工程 |
| 6 | 黑八 | s006 | 男 | 计算机科学与技术 |
| 7 | 黄九 | s007 | 女 | 数学 |
| 8 | 满十 | s008 | 男 | 英语 |
+----+--------+------------+-----+--------------------------+
关联表 teacher_course:
bash
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| course_id | int(11) | NO | | NULL | |
| teacher_id | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+----------------+
bash
+----+-----------+------------+
| id | course_id | teacher_id |
+----+-----------+------------+
| 1 | 1 | 3 |
| 2 | 3 | 3 |
| 3 | 2 | 2 |
| 4 | 4 | 2 |
| 5 | 5 | 4 |
+----+-----------+------------+
关联表 course_student:
bash
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| sudent_id | int(11) | NO | | NULL | |
| course_id | int(11) | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
bash
+----+-----------+-----------+
| id | sudent_id | course_id |
+----+-----------+-----------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 4 |
| 4 | 2 | 3 |
| 5 | 2 | 5 |
| 6 | 2 | 1 |
| 7 | 3 | 1 |
| 8 | 3 | 3 |
| 9 | 3 | 5 |
| 10 | 4 | 1 |
| 11 | 4 | 3 |
| 12 | 4 | 5 |
| 13 | 5 | 1 |
| 14 | 5 | 3 |
| 15 | 5 | 5 |
| 16 | 6 | 1 |
| 17 | 6 | 2 |
| 18 | 6 | 4 |
| 19 | 7 | 1 |
| 20 | 7 | 4 |
+----+-----------+-----------+
准备工作完成!!
INNER JOIN (内连接)
只返回n个表中满足连接条件的匹配行(简述:关联表里有多少满足条件的关联项,就会查出多少条对应数据),下面我们使用 INNER JOIN
来连接查询 老师对应的课程 和 教学所在教室:
- 只返回匹配的行: INNER JOIN 仅返回满足连接条件的行,即左表和右表中都存在匹配键值的行。不匹配的行将被排除在结果集之外。
- 基于连接条件: INNER JOIN 需要一个 ON 子句来指定连接条件。这个条件通常是比较两个表中某一列的值(如主键和外键),但也可以是任何逻辑表达式。
- 高效的查询性能: 由于 INNER JOIN 只处理匹配的行,因此它可以比其他类型的连接更高效,尤其是在处理大型数据集时。适当的索引可以进一步提高 INNER JOIN 的性能。
- 广泛使用: INNER JOIN 是最常见的连接类型,适用于大多数需要从多个表中检索相关数据的场景。它确保了结果集中只包含有效的、相互关联的数据。
- 对称性: INNER JOIN 对左右表的位置不敏感,即 A INNER JOIN B 和 B INNER JOIN A 会产生相同的结果集,前提是连接条件相同。
sql
SELECT a.name, c.title, c.classroom
FROM teacher a
INNER JOIN teacher_course ac
ON a.id = ac.teacher_id
INNER JOIN course c
ON ac.course_id = c.id
bash
+-----------+--------------------+--------------------------------+
| name | title | classroom |
+-----------+--------------------+--------------------------------+
| 白老师 | 高数 | 阶梯教室201 |
| 白老师 | 程控交换技术 | 通讯工程学院实验室203 |
| 李老师 | c语言 | 大课堂8811 |
| 李老师 | c语言进阶 | 大课堂8811 |
| 华老师 | 光通信 | 通讯工程学院实验室206 |
+-----------+--------------------+--------------------------------+
这里只显示有关联课程的老师,如果没有关联的课程(比如张老师),则不会显示。
LEFT JOIN (左连接) 也叫左外连接(left [outer] join)
返回左表中的所有记录,即使右表中没有匹配。如果右表中没有匹配,则结果为NULL。
- 保留左表的所有行: LEFT JOIN 会确保左表中的每一行都出现在结果集中,即使右表中没有相应的匹配行。对于那些在右表中找不到匹配项的左表行,右表的列将被填充为 NULL。
- 基于连接条件: LEFT JOIN 需要一个 ON 子句来指定连接条件。这个条件决定了哪些行被认为是“匹配”的,并且只有这些匹配的行会在结果集中共享数据。
- 部分 NULL 值: 如果左表中的一行在右表中没有找到匹配项,那么结果集中该行对应的右表列将包含 NULL 值。这有助于识别那些在右表中没有对应记录的左表行。
- 对称性: LEFT JOIN 和 RIGHT JOIN 是对称的操作。你可以通过交换两个表的位置并使用 RIGHT JOIN 来实现相同的结果。例如,A LEFT JOIN B 等效于 B RIGHT JOIN A。
- 广泛使用: LEFT JOIN 是一种非常常见的连接类型,适用于许多需要从多个表中检索相关数据的场景,特别是当你希望保留左表中的所有记录时。
sql
SELECT a.name, c.title, c.classroom
FROM teacher a
LEFT JOIN teacher_course ac
ON a.id = ac.teacher_id
LEFT JOIN course c
ON ac.course_id = c.id
bash
+-----------+--------------------+--------------------------------+
| name | title | classroom |
+-----------+--------------------+--------------------------------+
| 白老师 | 高数 | 阶梯教室201 |
| 白老师 | 程控交换技术 | 通讯工程学院实验室203 |
| 李老师 | c语言 | 大课堂8811 |
| 李老师 | c语言进阶 | 大课堂8811 |
| 华老师 | 光通信 | 通讯工程学院实验室206 |
| 张老师 | NULL | NULL |
+-----------+--------------------+--------------------------------+
这里张老师没有对应的课程,所以没有对应的记录。
查询一下 某个学生的所有课程信息:
sql
SELECT a.name, a.profession, c.title, c.classroom
FROM student a
LEFT JOIN course_student
ON a.id = course_student.sudent_id
LEFT JOIN course c
ON course_student.course_id = c.id
WHERE a.name = '张三'
bash
+--------+--------------+---------------+-----------------+
| name | profession | title | classroom |
+--------+--------------+---------------+-----------------+
| 张三 | 通信工程 | 高数 | 阶梯教室201 |
| 张三 | 通信工程 | c语言 | 大课堂8811 |
| 张三 | 通信工程 | c语言进阶 | 大课堂8811 |
+--------+--------------+---------------+-----------------+
会查询 左表(student)中在 右表(course_student) 中有对应记录的记录,如果没有,则返回NULL。
RIGHT JOIN (右连接) 也叫右外连接(right [outer] join)
返回右表中的所有记录,即使左表中没有匹配。如果左表中没有匹配,则结果为NULL。
- 保留右表的所有行: RIGHT JOIN 会确保右表中的每一行都出现在结果集中,即使左表中没有相应的匹配行。对于那些在左表中找不到匹配项的右表行,左表的列将被填充为 NULL。
- 基于连接条件: RIGHT JOIN 需要一个 ON 子句来指定连接条件。这个条件决定了哪些行被认为是“匹配”的,并且只有这些匹配的行会在结果集中共享数据。
- 对称性: RIGHT JOIN 和 LEFT JOIN 是对称的操作。你可以通过交换两个表的位置并使用 LEFT JOIN 来实现相同的结果。例如,A RIGHT JOIN B 等效于 B LEFT JOIN A。
- 可能产生部分 NULL 值: 如果右表中的一行在左表中没有找到匹配项,那么结果集中该行对应的左表列将包含 NULL 值。这有助于识别那些在左表中没有对应记录的右表行。
- 并非总是必要的: 在某些情况下,RIGHT JOIN 可能不是最直观的选择。由于它可以简单地通过交换表顺序并使用 LEFT JOIN 来替代,因此很多开发者更倾向于使用 LEFT JOIN,因为它通常更容易理解和维护。
sql
SELECT a.name, c.title, c.classroom
FROM teacher a
RIGHT JOIN teacher_course tc
ON a.id = tc.teacher_id
RIGHT JOIN course c
ON tc.course_id = c.id
bash
+-----------+--------------------+--------------------------------+
| name | title | classroom |
+-----------+--------------------+--------------------------------+
| 白老师 | 高数 | 阶梯教室201 |
| 李老师 | c语言 | 大课堂8811 |
| 白老师 | 程控交换技术 | 通讯工程学院实验室203 |
| 李老师 | c语言进阶 | 大课堂8811 |
| 华老师 | 光通信 | 通讯工程学院实验室206 |
| NULL | 水课 | 宿舍 |
+-----------+--------------------+--------------------------------+
查询某个课程有多少学生报名:
sql
SELECT a.name, a.profession, c.title, c.classroom
FROM student a
RIGHT JOIN course_student cs
ON a.id = cs.sudent_id
RIGHT JOIN course c
ON cs.course_id = c.id
WHERE c.title = '水课'
bash
+------+------------+--------+-----------+
| name | profession | title | classroom |
+------+------------+--------+-----------+
| NULL | NULL | 水课 | 宿舍 |
+------+------------+--------+-----------+
这里也可以用 LEFT JOIN 来实现,效果是一样的。
FULL JOIN (全连接) 也叫满连接(full [outer] join)
返回两个表中的所有记录,当没有匹配时,结果集中不匹配的那一侧将包含NULL (mysql 不直接支持。。。服啦)
- 保留所有行: FULL JOIN 会返回两个表中的所有记录,无论它们是否在另一个表中有匹配项。如果一个表中的一行在另一个表中没有找到匹配项,那么结果集中该行对应的另一表的列将填充 NULL。
- 结合 LEFT JOIN 和 RIGHT JOIN: 从某种意义上说,FULL JOIN 是 LEFT JOIN 和 RIGHT JOIN 的组合。它不仅包括左表的所有行(如 LEFT JOIN),还包括右表的所有行(如 RIGHT JOIN),并且对于两边都没有匹配的情况,使用 NULL 补充。
- 需要明确的连接条件: 尽管 FULL JOIN 会返回所有行,但通常你仍然需要提供一个 ON 子句来指定连接条件。这个条件决定了哪些行被认为是“匹配”的,并且只有这些匹配的行会在结果集中共享数据。
- 可能产生较大的结果集: 由于 FULL JOIN 包含了两个表中的所有行,因此结果集可能会非常大,尤其是在处理大型数据集时。这可能会对性能产生影响,因此在设计查询时应考虑这一点。
- 并非所有数据库都支持: 并不是所有的数据库系统都直接支持 FULL JOIN。例如,MySQL 不直接支持 FULL JOIN,但在某些情况下可以通过 UNION 操作结合 LEFT JOIN 和 RIGHT JOIN 来模拟 FULL JOIN 的效果。
Websites 表:
bash
+----+--------------+---------------------------+-------+---------+
| id | name | url | alexa | country |
+----+--------------+---------------------------+-------+---------+
| 1 | Google | https://www.google.cm/ | 1 | USA |
| 2 | 淘宝 | https://www.taobao.com/ | 13 | CN |
| 3 | 菜鸟教程 | http://www.runoob.com/ | 4689 | CN |
| 4 | 微博 | http://weibo.com/ | 20 | CN |
| 5 | Facebook | https://www.facebook.com/ | 3 | USA |
| 7 | stackoverflow | http://stackoverflow.com/ | 0 | IND |
+----+---------------+---------------------------+-------+---------+
access_log 网站访问记录表:
bash
+-----+---------+-------+------------+
| aid | site_id | count | date |
+-----+---------+-------+------------+
| 1 | 1 | 45 | 2016-05-10 |
| 2 | 3 | 100 | 2016-05-13 |
| 3 | 1 | 230 | 2016-05-14 |
| 4 | 2 | 10 | 2016-05-14 |
| 5 | 5 | 205 | 2016-05-14 |
| 6 | 4 | 13 | 2016-05-15 |
| 7 | 3 | 220 | 2016-05-15 |
| 8 | 5 | 545 | 2016-05-16 |
| 9 | 3 | 201 | 2016-05-17 |
+-----+---------+-------+------------+
9 rows in set (0.00 sec)
sql
SELECT Websites.name, access_log.count, access_log.date
FROM Websites
FULL OUTER JOIN access_log
ON Websites.id=access_log.site_id
ORDER BY access_log.count DESC;
FULL OUTER JOIN 关键字返回左表(Websites)和右表(access_log)中所有的行。如果 "Websites" 表中的行在 "access_log" 中没有匹配或者 "access_log" 表中的行在 "Websites" 表中没有匹配,也会列出这些行;
mysql 不能 full outer join,所以我们另聘蹊径:
sql
SELECT s.name, s.profession, c.title, c.classroom
FROM student s
LEFT JOIN course_student cs ON s.id = cs.sudent_id
LEFT JOIN course c ON cs.course_id = c.id
UNION
SELECT s.name, s.profession, c.title, c.classroom
FROM student s
RIGHT JOIN course_student cs ON s.id = cs.sudent_id
RIGHT JOIN course c ON cs.course_id = c.id
WHERE s.id IS NULL;
bash
+--------+--------------------------+--------------------+--------------------------------+
| name | profession | title | classroom |
+--------+--------------------------+--------------------+--------------------------------+
| 张三 | 通信工程 | 高数 | 阶梯教室201 |
| 张三 | 通信工程 | c语言 | 大课堂8811 |
| 张三 | 通信工程 | c语言进阶 | 大课堂8811 |
| 李四 | 通信工程 | 程控交换技术 | 通讯工程学院实验室203 |
| 李四 | 通信工程 | 光通信 | 通讯工程学院实验室206 |
| 李四 | 通信工程 | 高数 | 阶梯教室201 |
| 王五 | 通信工程 | 高数 | 阶梯教室201 |
| 王五 | 通信工程 | 程控交换技术 | 通讯工程学院实验室203 |
| 王五 | 通信工程 | 光通信 | 通讯工程学院实验室206 |
| 刘六 | 通信工程 | 高数 | 阶梯教室201 |
| 刘六 | 通信工程 | 程控交换技术 | 通讯工程学院实验室203 |
| 刘六 | 通信工程 | 光通信 | 通讯工程学院实验室206 |
| 毛七 | 通信工程 | 高数 | 阶梯教室201 |
| 毛七 | 通信工程 | 程控交换技术 | 通讯工程学院实验室203 |
| 毛七 | 通信工程 | 光通信 | 通讯工程学院实验室206 |
| 黑八 | 计算机科学与技术 | 高数 | 阶梯教室201 |
| 黑八 | 计算机科学与技术 | c语言 | 大课堂8811 |
| 黑八 | 计算机科学与技术 | c语言进阶 | 大课堂8811 |
| 黄九 | 数学 | 高数 | 阶梯教室201 |
| 黄九 | 数学 | c语言进阶 | 大课堂8811 |
| 满十 | 英语 | NULL | NULL |
| NULL | NULL | 水课 | 宿舍 |
+--------+--------------------------+--------------------+--------------------------------+
22 rows in set (0.02 sec)
SQL UNION 操作符合并两个或多个 SELECT 语句的结果。
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。它可以从多个表中选择数据,并将结果集组合成一个结果集。使用 UNION 时,每个 SELECT 语句必须具有相同数量的列,且对应列的数据类型必须相似。
CROSS JOIN 交叉连接
不带ON子句的CROSS JOIN会产生笛卡尔积,即左表的每一行与右表的每一行配对。如果加上ON子句,则等同于INNER JOIN。
- 产生笛卡尔积: CROSS JOIN 会生成两个表中所有行的组合。例如,如果表 A 有 3 行,表 B 有 4 行,那么 CROSS JOIN 的结果将包含 12 (3 x 4) 行。
- 不带 ON 子句: CROSS JOIN 不需要 ON 子句来指定连接条件,因为它本质上是无条件地将两个表的所有行进行组合。
- 等同于没有 WHERE 条件的内连接: 在某些数据库系统中,CROSS JOIN 可以通过省略 ON 子句的 JOIN 来实现。例如,SELECT * FROM table1 CROSS JOIN table2; 与 SELECT * FROM table1, table2; 是等效的。
- 可能导致大数据量: 如果两个表的行数都很大,CROSS JOIN 可能会导致非常大的结果集,这可能会对性能产生负面影响,并且在实际应用中很少直接使用。
- 用于特定场景: 虽然 CROSS JOIN 通常不是最常用的连接类型,但在某些情况下它是有用的,比如当你需要为每个记录创建一个固定数量的副本,或者当你确实需要所有可能的组合时。
先演示一下 不带 on 的:
sql
SELECT t.`name`, c.title
FROM teacher t CROSS JOIN course c
bash
+-----------+--------------------+
| name | title |
+-----------+--------------------+
| 张老师 | 高数 |
| 李老师 | 高数 |
| 白老师 | 高数 |
| 华老师 | 高数 |
| 张老师 | c语言 |
| 李老师 | c语言 |
| 白老师 | c语言 |
| 华老师 | c语言 |
| 张老师 | 程控交换技术 |
| 李老师 | 程控交换技术 |
| 白老师 | 程控交换技术 |
| 华老师 | 程控交换技术 |
| 张老师 | c语言进阶 |
| 李老师 | c语言进阶 |
| 白老师 | c语言进阶 |
| 华老师 | c语言进阶 |
| 张老师 | 光通信 |
| 李老师 | 光通信 |
| 白老师 | 光通信 |
| 华老师 | 光通信 |
| 张老师 | 水课 |
| 李老师 | 水课 |
| 白老师 | 水课 |
| 华老师 | 水课 |
+-----------+--------------------+
24 rows in set (0.01 sec)
注:笛卡尔积;直白点就是把左表和右表都列出来,然后两两配对,比如左表有3行,右表有5行,那么就生成15行。
下面用一下 带 ON 的:
sql
SELECT t.`name`, c.title, c.classroom
FROM teacher t
CROSS JOIN teacher_course tc
ON t.id = tc.teacher_id
CROSS JOIN course c
ON c.id = tc.course_id
bash
+-----------+--------------------+--------------------------------+
| name | title | classroom |
+-----------+--------------------+--------------------------------+
| 白老师 | 高数 | 阶梯教室201 |
| 白老师 | 程控交换技术 | 通讯工程学院实验室203 |
| 李老师 | c语言 | 大课堂8811 |
| 李老师 | c语言进阶 | 大课堂8811 |
| 华老师 | 光通信 | 通讯工程学院实验室206 |
+-----------+--------------------+--------------------------------+
5 rows in set (0.02 sec)
可见,和 INNER JOIN 一样
SELF JOIN 自连接
是一个表与它自身进行的连接,通常用于查找具有层次结构的数据,如组织结构或员工管理链。 在 SQL 中,自连接是一种特殊的 JOIN 操作,它允许一个表与它自身的一个或多个字段进行比较,从而实现对数据的分组和聚合。
- 同一个表的两次引用: 在 SELF JOIN 中,同一个表会被视为两个不同的实体来参与连接。为了区分这两个实体,通常会给表起别名(alias),以便可以在查询中分别引用它们。
- 用于表示层次关系: SELF JOIN 常用于表示一对多的关系,其中每个记录可以有一个父记录(或上级记录)。例如,在员工表中,每个员工可以有一个上级经理,而经理本身也是该表中的一名员工。
- 连接条件: 连接条件通常是基于一个外键字段,这个字段指向表中的另一个主键字段。例如,在员工表中,manager_id 可能是指向 employee_id 的外键。
- 避免重复列名冲突: 由于是在同一个表上进行连接,可能会出现列名冲突的情况。为了避免这种情况,使用表别名和列别名可以帮助清晰地指定每个列的来源。
- 递归层次结构: 对于更复杂的层次结构,如无限层级的分类或组织结构,可能需要使用递归查询(如SQL标准中的 WITH RECURSIVE)来遍历整个层次结构。
表结构:
bash
+-------------+--------------+------+-----+----------------------+--------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+----------------------+--------------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| createTime | datetime(6) | NO | | CURRENT_TIMESTAMP(6) | |
| updateTime | datetime(6) | NO | | CURRENT_TIMESTAMP(6) | on update CURRENT_TIMESTAMP(6) |
| type | int(11) | NO | | NULL | |
| status | int(11) | NO | | 0 | |
| title | varchar(50) | NO | | NULL | |
| value | varchar(50) | NO | | NULL | |
| parentId | int(11) | NO | | 0 | |
| description | varchar(255) | YES | | NULL | |
| sort | int(11) | YES | | 0 | |
+-------------+--------------+------+-----+----------------------+--------------------------------+
基本数据:
bash
+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-----------------+------+
| id | createTime | updateTime | type | status | title | value | parentId | description | sort |
+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-----------------+------+
| 1 | 2024-03-29 11:27:28.073025 | 2024-03-29 11:27:43.499535 | 0 | 0 | 行业 | industry | 0 | 行业字典项 | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 |
| 5 | 2024-04-01 09:59:23.798674 | 2024-04-01 09:59:23.798674 | 0 | 0 | 制造业 | manufacturing | 1 | NULL | 0 |
| 6 | 2024-04-01 09:59:44.634897 | 2024-04-01 09:59:44.634897 | 0 | 0 | 交运物流 | logistics | 1 | NULL | 0 |
| 7 | 2024-04-01 10:14:00.135731 | 2024-04-01 10:14:00.135731 | 0 | 0 | 通讯行业 | communication | 1 | NULL | 0 |
| 8 | 2024-04-01 10:14:50.871233 | 2024-04-01 10:14:50.871233 | 0 | 0 | 超大型 | Extra large | 3 | NULL | 0 |
| 9 | 2024-04-01 10:15:00.389472 | 2024-04-01 10:15:00.389472 | 0 | 0 | 大型 | large | 3 | NULL | 0 |
| 10 | 2024-04-01 10:15:16.022855 | 2024-04-01 10:15:16.022855 | 0 | 0 | 中型 | medium size | 3 | NULL | 0 |
| 11 | 2024-04-01 10:15:29.581758 | 2024-04-01 10:15:29.581758 | 0 | 0 | 小型 | small | 3 | NULL | 0 |
| 12 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 微型 | miniature | 3 | NULL | 0 |
| 13 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 会长 | President | 2 | NULL | 0 |
| 14 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 名誉会长 | Honorary President | 2 | NULL | 0 |
| 15 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 副会长 | Vice president | 2 | NULL | 0 |
| 16 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 理事 | director | 2 | NULL | 0 |
| 17 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 会员 | member | 2 | NULL | 0 |
| 18 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 智能制造 | intelligent | 4 | NULL | 0 |
| 19 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 生物医药 | biology | 4 | NULL | 0 |
| 20 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 金融投资 | finance | 4 | NULL | 0 |
| 21 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 轨道交通 | track | 4 | NULL | 0 |
| 22 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:28:06.907779 | 0 | 0 | 建设行业 | construction | 4 | NULL | 0 |
| 23 | 2024-04-15 19:37:03.758482 | 2024-05-13 20:50:44.665558 | 1 | 0 | 圈子分类 | FriendsClassify | 0 | NULL | 0 |
| 24 | 2024-04-15 19:37:44.916770 | 2024-05-13 20:50:49.870535 | 1 | 0 | 业务资源对接 | BusinessResourceDocking | 23 | NULL | 0 |
| 25 | 2024-04-15 19:38:00.025783 | 2024-05-13 20:50:52.175268 | 1 | 0 | 人才招聘 | Recruitment | 23 | NULL | 0 |
+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-----------------+------+
25 rows in set (0.00 sec)
下面使用自连接,不附加任何条件,查询全部数据:
sql
select *
FROM qinghe_dictionary a
JOIN qinghe_dictionary b
ON a.id = b.parentId
bash
+----+----------------------------+----------------------------+------+--------+--------------+-----------------+----------+-----------------+------+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-------------+------+
| id | createTime | updateTime | type | status | title | value | parentId | description | sort | id | createTime | updateTime | type | status | title | value | parentId | description | sort |
+----+----------------------------+----------------------------+------+--------+--------------+-----------------+----------+-----------------+------+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-------------+------+
| 1 | 2024-03-29 11:27:28.073025 | 2024-03-29 11:27:43.499535 | 0 | 0 | 行业 | industry | 0 | 行业字典项 | 0 | 5 | 2024-04-01 09:59:23.798674 | 2024-04-01 09:59:23.798674 | 0 | 0 | 制造业 | manufacturing | 1 | NULL | 0 |
| 1 | 2024-03-29 11:27:28.073025 | 2024-03-29 11:27:43.499535 | 0 | 0 | 行业 | industry | 0 | 行业字典项 | 0 | 6 | 2024-04-01 09:59:44.634897 | 2024-04-01 09:59:44.634897 | 0 | 0 | 交运物流 | logistics | 1 | NULL | 0 |
| 1 | 2024-03-29 11:27:28.073025 | 2024-03-29 11:27:43.499535 | 0 | 0 | 行业 | industry | 0 | 行业字典项 | 0 | 7 | 2024-04-01 10:14:00.135731 | 2024-04-01 10:14:00.135731 | 0 | 0 | 通讯行业 | communication | 1 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 | 8 | 2024-04-01 10:14:50.871233 | 2024-04-01 10:14:50.871233 | 0 | 0 | 超大型 | Extra large | 3 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 | 9 | 2024-04-01 10:15:00.389472 | 2024-04-01 10:15:00.389472 | 0 | 0 | 大型 | large | 3 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 | 10 | 2024-04-01 10:15:16.022855 | 2024-04-01 10:15:16.022855 | 0 | 0 | 中型 | medium size | 3 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 | 11 | 2024-04-01 10:15:29.581758 | 2024-04-01 10:15:29.581758 | 0 | 0 | 小型 | small | 3 | NULL | 0 |
| 3 | 2024-03-29 11:33:34.892866 | 2024-03-29 11:33:34.892866 | 0 | 0 | 规模 | scale | 0 | NULL | 0 | 12 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 微型 | miniature | 3 | NULL | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 | 13 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 会长 | President | 2 | NULL | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 | 14 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 名誉会长 | Honorary President | 2 | NULL | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 | 15 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 副会长 | Vice president | 2 | NULL | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 | 16 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 理事 | director | 2 | NULL | 0 |
| 2 | 2024-03-29 11:32:53.154392 | 2024-03-29 11:32:53.154392 | 0 | 0 | 职位 | position | 0 | NULL | 0 | 17 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 会员 | member | 2 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 | 18 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 智能制造 | intelligent | 4 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 | 19 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 生物医药 | biology | 4 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 | 20 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 金融投资 | finance | 4 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 | 21 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:15:42.507014 | 0 | 0 | 轨道交通 | track | 4 | NULL | 0 |
| 4 | 2024-03-29 11:34:57.600602 | 2024-03-29 11:34:57.600602 | 0 | 0 | 专委会 | special | 0 | NULL | 0 | 22 | 2024-04-01 10:15:42.507014 | 2024-04-01 10:28:06.907779 | 0 | 0 | 建设行业 | construction | 4 | NULL | 0 |
| 23 | 2024-04-15 19:37:03.758482 | 2024-05-13 20:50:44.665558 | 1 | 0 | 圈子分类 | FriendsClassify | 0 | NULL | 0 | 24 | 2024-04-15 19:37:44.916770 | 2024-05-13 20:50:49.870535 | 1 | 0 | 业务资源对接 | BusinessResourceDocking | 23 | NULL | 0 |
| 23 | 2024-04-15 19:37:03.758482 | 2024-05-13 20:50:44.665558 | 1 | 0 | 圈子分类 | FriendsClassify | 0 | NULL | 0 | 25 | 2024-04-15 19:38:00.025783 | 2024-05-13 20:50:52.175268 | 1 | 0 | 人才招聘 | Recruitment | 23 | NULL | 0 |
+----+----------------------------+----------------------------+------+--------+--------------+-----------------+----------+-----------------+------+----+----------------------------+----------------------------+------+--------+--------------------+-------------------------+----------+-------------+------+
20 rows in set (0.00 sec)
增加一条查询条件:
sql
select a.title, a.id as parent_id, b.title AS son_title , b.id as son_id
FROM qinghe_dictionary a
JOIN qinghe_dictionary b
ON a.id = b.parentId
WHERE a.id = 1
bash
+--------+-----------+--------------+--------+
| title | parent_id | son_title | son_id |
+--------+-----------+--------------+--------+
| 行业 | 1 | 制造业 | 5 |
| 行业 | 1 | 交运物流 | 6 |
| 行业 | 1 | 通讯行业 | 7 |
+--------+-----------+--------------+--------+
3 rows in set (0.01 sec)
NATURAL JOIN
NATURAL JOIN 是一种特殊的 JOIN,它根据两个表具有相同名称的列来匹配行。它与等值 JOIN 类似,但不需要指定列名。但是,它只适用于两个表具有相同名称的列的情况。 自动匹配同名列:
- 不指定连接条件: 由于 NATURAL JOIN 自动处理连接条件,因此查询语句中不需要 ON 子句。这简化了编写查询的过程,但也可能导致意外的结果,特别是当表之间存在多个同名列时。
- 结果集中列的处理: 在结果集中,NATURAL JOIN 只保留一份来自连接条件的列(即同名列)。这意味着如果两个表都有一个名为 id 的列,那么在结果集中只会有一个 id 列,而不是两个。
- 潜在的问题: 如果两个表之间的同名列不是预期的连接键,或者有多个可能的连接键,NATURAL JOIN 可能会导致非预期的结果。此外,如果两个表之间没有任何同名列,NATURAL JOIN 将产生空的结果集,因为它找不到任何可以连接的条件。
- 性能考虑: NATURAL JOIN 的性能取决于数据库系统的实现。在某些情况下,它可能会比明确指定连接条件的 JOIN 慢,因为在执行 NATURAL JOIN 时,数据库需要额外的工作来识别同名列。
假设我们有两个表 employees 和 departments,它们都包含一个名为 department_id 的列,代表部门ID。 -- 表 employees
bash
+----+----------------+---------------+
| id | name | department_id |
+----+----------------+---------------+
| 1 | John Doe | 10 |
| 2 | Jane Smith | 20 |
| 3 | Alice Johnson | 10 |
+----+----------------+---------------+
-- 表 departments
bash
+----+----------------+
| id | department_name|
+----+----------------+
| 10 | Sales |
| 20 | Marketing |
+----+----------------+
sql
SELECT * FROM employees NATURAL JOIN departments;
bash
+----+----------------+---------------+----------------+
| id | name | department_id | department_name|
+----+----------------+---------------+----------------+
| 1 | John Doe | 10 | Sales |
| 2 | Jane Smith | 20 | Marketing |
| 3 | Alice Johnson | 10 | Sales |
+----+----------------+---------------+----------------+