CodeGym /课程 /SQL SELF /处理 NULL值在数据合并时

处理 NULL值在数据合并时

SQL SELF
第 12 级, 课程 0
可用

想象一下,你要合并两张表:students(学生)和enrollments(课程报名)。如果enrollments表里没有某个学生的信息,但你用了比如LEFT JOIN,那students表的行还是会出来,但enrollments的信息就没了。这种情况下就会出现NULL。

大概长这样:

表students:

id name
1 Eva
2 Peter
3 Anna

表enrollments:

student_id course_name
1 数学
1 信息学
2 物理

用LEFT JOIN的查询:

SELECT students.id, students.name, enrollments.course_name
FROM students
LEFT JOIN enrollments ON students.id = enrollments.student_id;

结果:

id name course_name
1 Eva 数学
1 Eva 信息学
2 Peter 物理
3 Anna NULL

哈喽,NULL!你看,Anna没报任何课程,课程信息就没了,显示出来就是NULL。

NULL对查询有啥影响?

NULL不是“0”也不是“空字符串”,它是没有值。这种行为有点意思(有时候还挺烦人的):

和NULL比较:

如果你写WHERE course_name = NULL,查不出来NULL的行。为啥?因为NULL不能直接比较。

要判断是不是NULL,得用特殊操作符:

WHERE course_name IS NULL

数学运算:

任何和NULL的运算结果都是NULL。比如:

SELECT 5 + NULL; -- 结果: NULL

聚合函数:

大多数聚合函数,比如SUM()、AVG(),会忽略NULL,但COUNT(*)会把它们当作“有这行”。

怎么搞定NULL?

  1. 用COALESCE()把NULL换成更友好的值

COALESCE()函数可以把NULL替换成别的值。比如课程没了,可以写"没有课程":

SELECT
    students.id, 
    students.name, 
    COALESCE(enrollments.course_name, '没有课程') AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

结果:

id name course_name
1 Eva 数学
1 Eva 信息学
2 Peter 物理
3 Anna 没有课程

现在看起来舒服多了吧?

  1. 过滤NULL值

如果你不想看到NULL的行,可以用WHERE ... IS NOT NULL。比如:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id
WHERE 
    enrollments.course_name IS NOT NULL;

结果:

id name course_name
1 Eva 数学
1 Eva 信息学
2 Peter 物理

Anna就没了,因为她没有任何课程记录。

  1. 统计时考虑NULL:COUNT例子

前面说过,有些函数会忽略NULL,有些不会。比如:

要统计所有行,包括NULL:

SELECT COUNT(*) FROM students; -- 统计所有行(包括`course_name` = NULL的)

只统计没有NULL的行:

SELECT COUNT(course_name) FROM enrollments;
  1. 用CASE写条件表达式

如果你不喜欢COALESCE()或者想更灵活点,可以用CASE。比如:

SELECT
    students.id, 
    students.name,
    CASE
        WHEN enrollments.course_name IS NULL THEN '没有课程'
        ELSE enrollments.course_name
    END AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

结果和用COALESCE()一样,但CASE能写更复杂的规则。

  1. 如果你确定不会有NULL,用INNER JOIN

最极端的办法就是根本不让NULL出现,直接用INNER JOIN。这种JOIN只返回两张表都有匹配的行:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students INNER JOIN enrollments 
    ON students.id = enrollments.student_id;

没有意外——只有报了课程的学生。

结果:

id name course_name
1 Eva 数学
1 Eva 信息学
2 Peter 物理

如果你需要显示所有数据,包括NULL,那INNER JOIN就不适合,但有时候这就够了。

2
任务
SQL SELF, 第 12 级, 课程 0
已锁定
使用 `COALESCE` 替换 `NULL` 值
使用 `COALESCE` 替换 `NULL` 值
2
任务
SQL SELF, 第 12 级, 课程 0
已锁定
统计没有选课的学生数量(使用 `COUNT`)
统计没有选课的学生数量(使用 `COUNT`)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION