外部连接的原因
顺便说一句,你还记得我们合并电子表格时办公室清洁任务因为没有清洁工而消失了吗?
如果您运行这样的查询:
SELECT * FROM task
然后我们得到这个结果:
ID | emploee_id | 姓名 | 最后期限 |
---|---|---|---|
1个 | 1个 | 修复一个前端bug | 2022-06-01 |
2个 | 2个 | 修复后端的一个bug | 2022-06-15 |
3个 | 5个 | 买咖啡 | 2022-07-01 |
4个 | 5个 | 买咖啡 | 2022-08-01 |
5个 | 5个 | 会买咖啡 | 2022-09-01 |
6个 | (无效的) | 打扫办公室 | (无效的) |
7 | 4个 | 享受生活 | (无效的) |
8个 | 6个 | 享受生活 | (无效的) |
如果我们尝试通过 employee_id 连接任务表和员工表,“Clear Office”任务就会消失。
为解决此问题,已将各种修饰符添加到 JOIN 运算符中,以允许此类孤立行在不成对的情况下存储在另一个表中。
让我提醒您 JOIN 运算符的经典形式:
table 1 JOIN table 2 ON
condition
我们可以告诉 SQL Server 确保左表 (table1) 中的所有数据都存在于连接表中。即使在右表中没有它们的对。为此,您只需要编写:
table 1 LEFT JOIN table 2 ON condition
如果您希望连接表具有右表中的所有行,那么您需要编写:
table 1 RIGHT JOIN table 2 ON
condition
让我们编写一个查询来组合所有任务和员工,这样没有执行者的任务就不会丢失。为此,编写一个查询:
SELECT * FROM employee e RIGHT JOIN task t ON e.id = t.emploee_id
这个查询的结果是:
ID | 姓名 | 职业 | 薪水 | 年龄 | 加入日期 | ID | emploee_id | 姓名 |
---|---|---|---|---|---|---|---|---|
1个 | 伊万诺夫伊万 | 程序员 | 100000 | 25 | 2012-06-30 | 1个 | 1个 | 修复一个前端bug |
2个 | 彼得罗夫彼得 | 程序员 | 80000 | 23 | 2013-08-12 | 2个 | 2个 | 修复后端的一个bug |
4个 | 拉比诺维奇·莫伊沙 | 导演 | 200000 | 35 | 2015-05-12 | 7 | 4个 | 享受生活 |
5个 | 基连科阿纳斯塔西娅 | 办公室主管 | 40000 | 25 | 2015-10-10 | 3个 | 5个 | 买咖啡 |
5个 | 基连科阿纳斯塔西娅 | 办公室主管 | 40000 | 25 | 2015-10-10 | 4个 | 5个 | 买咖啡 |
5个 | 基连科阿纳斯塔西娅 | 办公室主管 | 40000 | 25 | 2015-10-10 | 5个 | 5个 | 买咖啡 |
6个 | 瓦斯卡 | 猫 | 1000 | 3个 | 2018-11-11 | 8个 | 6个 | 享受生活 |
(无效的) | (无效的) | (无效的) | (无效的) | (无效的) | (无效的) | 6个 | (无效的) | 打扫办公室 |
我们的表又增加了一行,有趣的是,里面有很多NULL值。从员工表中获取的所有数据都显示为 NULL,因为员工表中没有执行“清洁办公室”任务的执行者。
加入类型
共有 4 种类型的 JOIN。它们如下表所示:
简要条目 | 长条目 | 解释 | |
---|---|---|---|
1个 | 加入 | 内部联接 | 仅表 A 和 B 中的记录 |
2个 | 左连接 | 左外连接 | 表 A 中没有一对的所有行必须是 |
3个 | 正确加入 | 右外连接 | 表 B 中没有一对的所有行必须是 |
4个 | 外部连接 | 全外连接 | 表 A 和 B 中的所有碱基对行必须是 |
为了简单起见,如果我们将表表示为集合,那么 JOIN 可以显示为一张图片:

集合交集意味着对于一个表,它所引用的另一个表中有一条对应的记录。
采访中的问题
有时,新手程序员在面试时会被一个非常简单的问题轰炸。鉴于我们的表格,它可以表述如下:
“编写一个查询,显示没有任务的所有员工的列表。” 首先,让我们尝试稍微改写一下这个问题:“编写一个查询,显示employee 表中没有任务的所有员工的列表 task 表。” 我们需要得到这个集合:
有很多方法可以解决这个问题,但我将从最简单的开始:首先,您可以使用 LEFT JOIN 连接我们的表,然后使用 WHERE 排除所有用 NULL 填充缺失数据的行。
SELECT * FROM employee e LEFT JOIN task t ON e.id = t.emploee_id
WHERE t.id IS NULL
这个查询的结果是:
ID | 姓名 | 职业 | 薪水 | 年龄 | 加入日期 | ID | emploee_id | 姓名 |
---|---|---|---|---|---|---|---|---|
3个 | 伊万诺夫谢尔盖 | 测试员 | 40000 | 三十 | 2014-01-01 | (无效的) | (无效的) | (无效的) |
这个解决方案的唯一缺点是这里表中的行包含 NULL,并且根据条件我们需要显示员工列表。
为此,要么需要在 SELECT 中列出 employee 表所需的列,要么需要显示所有列,可以编写如下构造:
SELECT e.* FROM employee e, task t
完整的请求将如下所示:
SELECT e.*
FROM employee e RIGHT JOIN task t ON e.id = t.emploee_id
WHERE t.id IS NULL
此查询的结果:
ID | 姓名 | 职业 | 薪水 | 年龄 | 加入日期 |
---|---|---|---|---|---|
3个 | 伊万诺夫谢尔盖 | 测试员 | 40000 | 三十 | 2014-01-01 |
其余的方法留给你做功课。我不想剥夺您自己找到它们的乐趣。
GO TO FULL VERSION