0

Trino SQL Bài học 10: Xử lý giá trị NULL (IS NULL, COALESCE, NULLIF)

Mục tiêu bài học:

  • Hiểu đúng bản chất của NULL trong thế giới cơ sở dữ liệu quan hệ và phân tán.

  • Nắm vững cách lọc và đối chiếu các bản ghi chứa dữ liệu khuyết thiếu một cách an toàn.

  • Sử dụng thành thạo COALESCE để thiết lập giá trị mặc định (fallback).

  • Sử dụng NULLIF để tránh các lỗi tính toán nghiêm trọng (như lỗi chia cho 0).

1. Bản chất của NULL (Sự vô định)

Sai lầm lớn nhất của người mới học SQL là coi NULL tương đương với số 0 hoặc một chuỗi rỗng ('').

Trong chuẩn ANSI SQL (và Trino tuân thủ tuyệt đối), NULL mang ý nghĩa là "Không xác định" (Unknown) hoặc "Khuyết thiếu" (Missing).

Bởi vì NULL là vô định, bạn không thể mang sự vô định ra so sánh với bất kỳ thứ gì, kể cả với chính nó.

  • 10 > NULL →\rightarrow Kết quả là UNKNOWN.

  • NULL = NULL →\rightarrow Kết quả là UNKNOWN.

Nếu kết quả của mệnh đề WHERE là UNKNOWN, Trino sẽ loại bỏ dòng dữ liệu đó (giống hệt như khi kết quả là FALSE).

2. Nhận diện an toàn với IS NULL / IS NOT NULL

Vì toán tử = không có tác dụng với NULL, bạn bắt buộc phải dùng toán tử chuyên biệt IS NULL để kiểm tra sự tồn tại của dữ liệu khuyết thiếu.

Lọc các bản ghi bị thiếu dữ liệu:

Tìm các khách hàng chưa được cập nhật số điện thoại.

SQL

SELECT name, phone
FROM tpch.tiny.customer
WHERE phone IS NULL;

Lọc các bản ghi có dữ liệu hợp lệ:

Tìm các khách hàng đã có số điện thoại.

SQL

SELECT name, phone
FROM tpch.tiny.customer
WHERE phone IS NOT NULL;

Lưu ý: Tuyệt đối không viết WHERE phone = NULL hay WHERE phone <> NULL. Trino sẽ không báo lỗi cú pháp, nhưng truy vấn của bạn sẽ luôn trả về 0 dòng kết quả (Empty Set).

3. Lấp đầy khoảng trống với COALESCE

Khi trình bày dữ liệu lên Dashboard hoặc trả API về cho Frontend, việc hiển thị chữ NULL trống hoác thường gây trải nghiệm không tốt, hoặc gây lỗi Null Pointer Exception ở hệ thống downstream.

Hàm COALESCE(value1, value2, ..., value_n) sẽ duyệt qua danh sách các đối số từ trái sang phải và trả về giá trị đầu tiên KHÔNG PHẢI là NULL.

SQL

-- Nếu số điện thoại bị NULL, trả về chuỗi 'Chưa cập nhật'
SELECT 
    name, 
    COALESCE(phone, 'Chưa cập nhật') AS contact_info
FROM tpch.tiny.customer;

Bạn có thể truyền vào nhiều đối số. Hàm sẽ liên tục "rơi" (fallback) xuống mức tiếp theo cho đến khi tìm được dữ liệu thực.

SQL

-- Lấy số điện thoại di động, nếu NULL thì lấy điện thoại bàn, 
-- nếu vẫn NULL thì lấy email, cuối cùng mới trả về 'No Contact'.
SELECT 
    name, 
    COALESCE(mobile_phone, desk_phone, email, 'No Contact') AS primary_contact
FROM users;

Ràng buộc của Trino: Tất cả các đối số truyền vào COALESCE phải có cùng kiểu dữ liệu. Bạn không thể truyền tham số đầu là kiểu số nguyên (INTEGER) và tham số dự phòng là chuỗi (VARCHAR).

4. Chủ động tạo NULL với NULLIF

Nếu COALESCE dùng để "xóa" NULL, thì NULLIF(value1, value2) lại dùng để "tạo ra" NULL.

Hàm này so sánh hai giá trị:

  • Nếu value1 = value2, trả về NULL.

  • Nếu value1 <> value2, trả về value1.

Ứng dụng thực tế lớn nhất: Tránh lỗi chia cho 0 (Divide by Zero).

Trong tính toán tài chính, nếu bạn lấy doanh thu chia cho số lượng (nhưng số lượng bằng 0), Trino sẽ lập tức báo lỗi và dừng (fail) toàn bộ tiến trình truy vấn.

Thay vì viết hàm IF/ELSE phức tạp, bạn dùng NULLIF để biến số 0 thành NULL. Trong toán học của SQL, một số chia cho NULL sẽ ra kết quả NULL (không gây gián đoạn hệ thống).

SQL

-- Tính đơn giá trung bình: tổng tiền / số lượng
-- Nếu quantity = 0, NULLIF biến nó thành NULL. Phép chia sẽ trả về NULL một cách an toàn.
SELECT 
    orderkey,
    totalprice,
    quantity,
    totalprice / NULLIF(quantity, 0) AS unit_price
FROM order_details;

5. Cạm bẫy của NULL trong tính toán và tổng hợp

Bạn cần nhớ hai quy tắc toán học quan trọng khi dữ liệu có chứa NULL:

  1. Phép toán học thông thường lan truyền NULL: Bất kỳ phép cộng, trừ, nhân, chia nào với NULL đều ra NULL. (Ví dụ: 10 + 5 + NULL = NULL). Nếu bạn cần cộng dồn, hãy bọc COALESCE xung quanh.

  2. Các hàm tổng hợp (Aggregate) bỏ qua NULL: Các hàm như SUM(), AVG(), COUNT(cột) sẽ tự động phớt lờ các dòng có giá trị NULL. (Ví dụ: Trung bình cộng AVG() sẽ chỉ lấy tổng chia cho số lượng các dòng có chứa dữ liệu thực).

(Chi tiết về hàm tổng hợp sẽ được trình bày sâu hơn ở Bài 16).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí