学习过程中,遇到的问题,值得注意的点

JOIN VS LEFT JOIN

在数据库中,LEFT JOIN 和普通的 JOIN(默认是 INNER JOIN)是两种不同的连接方式,用来组合两个或多个表的数据。它们的区别主要在于是否保留左表中的所有记录


🔹 JOININNER JOIN(内连接)

  • 只返回两个表中“匹配”的记录

  • 如果某一行在其中一个表中没有匹配项,该行就不会出现在结果中

示例:

1
2
3
SELECT *
FROM A
JOIN B ON A.id = B.a_id;

结果:只包含 A 和 B 表中 id 匹配的行。


🔸 LEFT JOIN(左连接)

  • 返回左表中的所有记录,即使在右表中没有匹配项。

  • 如果右表没有匹配的记录,则右表的字段为 NULL

示例:

1
2
3
SELECT *
FROM A
LEFT JOIN B ON A.id = B.a_id;

结果:包含 A 表的所有记录,若 B 中有匹配则带上 B 表的数据;若没有匹配,则 B 表的字段为 NULL


表 A(学生):

id name
1 小明
2 小红
3 小刚

表 B(成绩):

a_id score
1 90
2 85

INNER JOIN 查询结果:

1
SELECT * FROM A JOIN B ON A.id = B.a_id;
id name a_id score
1 小明 1 90
2 小红 2 85

LEFT JOIN 查询结果:

1
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id;
id name a_id score
1 小明 1 90
2 小红 2 85
3 小刚 NULL NULL

✅ 总结一句话:

  • JOIN(默认是 INNER JOIN):只取匹配的记录

  • LEFT JOIN保留左表所有记录,右表无匹配时补 NULL

GROUP BY AND HAVING

GROUP BY 是 SQL 中用来对查询结果进行分组的关键字,通常会和聚合函数(如 COUNT()SUM()AVG()MAX()MIN() 等)一起使用,用来对每个组进行统计或运算

WHERE 是在分组前过滤数据,而 HAVING 是在分组后过滤数据。


🔹 基本语法

1
2
3
SELECT 列名, 聚合函数(...)
FROM 表名
GROUP BY 列名;

销售表 sales

id seller amount
1 张三 100
2 李四 200
3 张三 150
4 王五 300

❓ 统计每个人的销售总额:

1
2
3
SELECT seller, SUM(amount) AS total_sales
FROM sales
GROUP BY seller;

查询结果:

seller total_sales
张三 250
李四 200
王五 300

🧠 注意事项

  1. GROUP BY 后面的字段,必须是你在 SELECT 中使用的非聚合字段。

  2. 如果你在 SELECT 中用了非聚合字段,它必须出现在 GROUP BY 中(除非你使用了某些数据库的特殊语法,比如 MySQL 的 ONLY_FULL_GROUP_BY 没开启时可以例外)。


🔍 常见聚合函数搭配用法

常用聚合函数表

函数名 作用
COUNT(*) 统计每组的记录数
SUM() 求和
AVG() 计算平均值
MAX() 获取最大值
MIN() 获取最小值

每个函数都用于对一组值执行计算,并返回单个值,通常与GROUP BY子句一起使用。

✨ 进阶用法:配合 HAVING 使用

WHERE 是在分组前过滤数据,而 HAVING 是在分组后过滤数据。

举例:只查出销售额超过 200 的销售员

1
2
3
4
SELECT seller, SUM(amount) AS total_sales
FROM sales
GROUP BY seller
HAVING total_sales > 200;

✅ 总结一句话:

  • GROUP BY 是用来把结果按某一列分组的;

  • 通常结合聚合函数使用;

  • 如果你想对分组后的结果再筛选,记得用 HAVING 而不是 WHERE

EXISTS AND NOT EXISTS

EXISTSNOT EXISTS 是 SQL 中非常有用的子查询语法,用于判断某个子查询是否返回结果,结果为布尔值:存在则为 TRUE,否则为 FALSE


🔹 EXISTS 的作用

EXISTS 判断子查询是否返回至少一行记录

1
2
3
4
5
6
7
SELECT *
FROM 表A
WHERE EXISTS (
SELECT 1
FROM 表B
WHERE 表B.条件 = 表A.条件
);

📌 只要子查询结果存在任何一行EXISTS 就返回 TRUE,当前行就会被选中。


示例

表:students

id name
1 小明
2 小红
3 小刚

表:scores

student_id score
1 90
1 85
2 78

❓ 找出有成绩记录的学生:

1
2
3
4
5
6
7
SELECT *
FROM students s
WHERE EXISTS (
SELECT 1
FROM scores sc
WHERE sc.student_id = s.id
);

查询结果:

id name
1 小明
2 小红

✅ 小刚没有成绩记录,所以被排除了。

这个查询使用了 EXISTS 子查询,它会检查对于 students 表中的每个学生,scores 表中是否存在对应的记录。只有当存在匹配的记录时,该学生才会被包含在结果中。

🔸 NOT EXISTS 的作用

NOT EXISTS 判断子查询是否不返回任何结果,即判断“不存在”

1
2
3
4
5
6
7
SELECT *
FROM 表A
WHERE NOT EXISTS (
SELECT 1
FROM 表B
WHERE 表B.条件 = 表A.条件
);

🌰 示例

继续用上面的表:

❓ 想找出没有成绩记录的学生

1
2
3
4
5
6
7
SELECT *
FROM students s
WHERE NOT EXISTS (
SELECT 1
FROM scores sc
WHERE sc.student_id = s.id
);

查询结果:

id name
3 小刚

✅ 因为小刚在 scores 表中找不到成绩记录。


💡 EXISTS vs IN vs JOIN 简要比较

用法 推荐场景
EXISTS 子查询结果比较复杂、带多个字段时
IN 子查询只返回单列,且数据量不大时
JOIN 需要获取两个表的具体字段值时

这个查询使用了 NOT EXISTS 子查询,它会检查对于 students 表中的每个学生,在 scores 表中是否不存在对应的记录。只有当没有匹配的记录时,该学生才会被包含在结果中

三种查询方式的比较:

  1. EXISTS:适合条件复杂的子查询,效率较高
  2. IN:适合简单的单列值匹配,数据量小时使用
  3. JOIN:需要同时获取两个表的字段时最合适

🔧 一般来说,EXISTS 在处理是否存在逻辑时更高效,尤其是在子查询中带有复杂条件或多个表联结的时候。