Chuyển đến nội dung chính
Mô-đun 4 · Bài học 2 trong tổng số 414/57 trong khóa học~10 min
Bài học theo mô-đun (2/4)

Xử lý NULL: IS NULL và COALESCE

Trong tập dữ liệu employees, Andrea Costa rất đặc biệt: anh ấy có department_id = NULL. Bạn đã chạm vào NULL (với LEFT JOIN), nhưng đã đến lúc phải xem xét vấn đề này một cách nghiêm túc: NULLs trong SQL hành xử khác với bất kỳ giá trị nào khác và bỏ qua chúng là một trong những nguyên nhân hàng đầu gây ra lỗi trong mã sản xuất.

NULL không phải là 0, không phải chuỗi rỗng

NULL có nghĩa là giá trị không xác định/thiếu. Không phải 0, không phải '', không phải false. Đó là "Tôi không biết". Từ đây rút ra một tính chất đáng ngạc nhiên: NULL không bằng bất cứ thứ gì, kể cả chính nó.

SQL
-- All these expressions return NULL (not true!):
SELECT NULL = NULL;       -- NULL
SELECT NULL = 0;          -- NULL
SELECT NULL <> 'qualcosa'; -- NULL

Hậu quả cụ thể: WHERE column = NULL không bao giờ có tác dụng. Bạn phải sử dụng các toán tử chuyên dụng IS NULL / IS NOT NULL:

SQL
-- Employees without a department:
SELECT first_name, last_name
FROM   employees
WHERE  department_id IS NULL;

-- Employees WITH a department:
SELECT first_name, last_name
FROM   employees
WHERE  department_id IS NOT NULL;

COALESCE - dự phòng NULL

Thường thì bạn muốn hiển thị thứ gì đó thay vì NULL khi dữ liệu được thiếu: chuỗi '(none)', số 0, ngày mặc định. Chức năng đó chính xác đây là COALESCE(a, b, c, ...): nó trả về đầu tiên đối số không NULL trong danh sách.

SQL
-- Show the department_id, or 0 if missing:
SELECT first_name, last_name, COALESCE(department_id, 0) AS dept
FROM   employees;

Kết hợp với LEFT JOIN nó trở nên vô cùng mạnh mẽ đối với các báo cáo:

SQL
SELECT e.first_name,
       e.last_name,
       COALESCE(d.name, '(nessun dipartimento)') AS dipartimento
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id;

Kết quả: tất cả nhân viên được trả về, kèm theo tên bộ phận hoặc thông tin rõ ràng nhãn cho những ai chưa có.

NULL và tổng hợp

Các hàm tổng hợp bỏ qua NULLs (ngoại trừ COUNT(*)):

  • COUNT(department_id) chỉ đếm các hàng có giá trị;
  • AVG(salary) trung bình bỏ qua NULLs — nó không coi chúng là 0;
  • SUM(...) chỉ tính tổng các giá trị không phải NULL.

Đây gần như luôn luôn là những gì bạn muốn. Nhưng thật tốt khi biết: nếu bạn đang tìm kiếm "tổng số nhân viên" sử dụng COUNT(*), không phải COUNT(department_id).

Hãy thử nó

tập thể dục#sql.m4.l2.e1
Nỗ lực: 0Đang tải…

Đối với mỗi nhân viên, hãy hiển thị tên (first_name), họ (last_name) và cột 'dipartimento_id' bằng với Department_id của họ hoặc -1 nếu không được chỉ định. Ba cột, một hàng cho mỗi nhân viên.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

Sử dụng COALESCE(department_id, -1) để thay thế NULL bằng -1.

Giải pháp khả dụng sau 3 lần thử

Xem lại bài tập

tập thể dục#sql.m4.l2.e2
Nỗ lực: 0Đang tải…

Trả về tên (first_name), họ (last_name) và tên bộ phận (departments.name) của TẤT CẢ nhân viên, hiển thị '(nessuno)' khi bộ phận đó bị thiếu. Sử dụng LEFT JOIN + COALESCE.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

COALESCE(d.name, '(nessuno)') xử lý NULL được giới thiệu bởi LEFT JOIN.

Giải pháp khả dụng sau 3 lần thử