COALESCE trong PostgreSQL: Hướng Dẫn Toàn Diện Từ A–Z

Avatar
namph
Junior

1. COALESCE là gì?

COALESCE là một hàm tích hợp (built-in function) trong PostgreSQL trả về giá trị không NULL đầu tiên trong danh sách các biểu thức được truyền vào.
Nếu tất cả các tham số đều là NULL, hàm trả về NULL.

COALESCE tuân theo chuẩn SQL và hoạt động tương tự trên hầu hết các hệ quản trị cơ sở dữ liệu quan hệ khác như MySQL, Oracle, SQL Server.

2. Cú pháp


COALESCE(value1, value2, ..., valueN)
  • Nhận một hoặc nhiều tham số.
  • Trả về giá trị không NULL đầu tiên từ trái sang phải.
  • Kiểu dữ liệu trả về là kiểu chung (common type) của tất cả các tham số.

3. Ví dụ cơ bản

SELECT COALESCE(NULL, NULL, 'PostgreSQL', 'DBA');
-- Kết quả: 'PostgreSQL'

SELECT COALESCE(NULL, 42, NULL);
-- Kết quả: 42

SELECT COALESCE(NULL, NULL, NULL);
-- Kết quả: NULL

4. Ứng dụng thực tế

4.1 Thay thế giá trị NULL bằng giá trị mặc định

Đây là use-case phổ biến nhất khi làm việc với dữ liệu có cột nullable.


SELECT
    first_name,
    COALESCE(phone_number, 'Chưa cung cấp') AS phone_number
FROM customers;

Nếu phone_number là NULL, kết quả hiển thị là 'Chưa cung cấp' thay vì NULL.

4.2 Kết hợp nhiều cột ưu tiên (Fallback Chain)


SELECT
    user_id,
    COALESCE(nickname, full_name, email, 'Người dùng ẩn danh') AS display_name
FROM users;

Hệ thống sẽ ưu tiên nickname, nếu NULL thì dùng full_name, rồi email, cuối cùng là chuỗi mặc định.

4.3 Tính toán an toàn với NULL

NULL trong phép toán số học luôn trả về NULL. Dùng COALESCE để tránh lỗi:


SELECT
    order_id,
    quantity * COALESCE(unit_price, 0) AS total_price
FROM order_items;

4.4 Dùng trong mệnh đề WHERE


SELECT * FROM employees
WHERE COALESCE(department_id, 0) = 0;
-- Lấy nhân viên chưa có phòng ban (NULL hoặc 0)

4.5 Dùng trong GROUP BY và tổng hợp dữ liệu


SELECT
    COALESCE(department, 'Không xác định') AS department,
    COUNT(*) AS total_employees
FROM employees
GROUP BY COALESCE(department, 'Không xác định');

4.6 Dùng trong UPDATE để bảo toàn giá trị cũ

UPDATE products
SET
    name        = COALESCE($1, name),
    description = COALESCE($2, description),
    price       = COALESCE($3, price)
WHERE product_id = $4;

Pattern này thường gặp trong các API PATCH — chỉ cập nhật các trường được cung cấp.

5. COALESCE vs NULLIF — Phân biệt hai hàm hay nhầm lẫn

HàmMục đíchVí dụ
COALESCE(a, b)Trả về a nếu a không NULL, ngược lại trả về bCOALESCE(NULL, 5) → 5
NULLIF(a, b)Trả về NULL nếu a = b, ngược lại trả về aNULLIF(5, 5) → NULL

Kết hợp hai hàm để tránh lỗi chia cho 0:

SELECT total_sales / NULLIF(COALESCE(total_orders, 0), 0) AS avg_sale;

6. COALESCE vs CASE WHEN

COALESCE(a, b) tương đương với:
CASE WHEN a IS NOT NULL THEN a ELSE b END

Tuy nhiên, COALESCE ngắn gọn hơn và được PostgreSQL optimizer nhận diện, tối ưu hiệu quả hơn trong nhiều trường hợp.

7. Hiệu năng và lưu ý quan trọng

7.1 Short-circuit evaluation

PostgreSQL đánh giá các tham số từ trái sang phải và dừng lại khi tìm thấy giá trị không NULL. Đặt biểu thức rẻ (cheap) ở trước, đắt (expensive) ở sau.

-- Tốt: cột đơn giản trước, subquery sau
SELECT COALESCE(cached_value, (SELECT compute_heavy_value(id))) FROM table;

7.2 Kiểu dữ liệu phải tương thích

Tất cả các tham số phải có kiểu dữ liệu có thể ép kiểu ngầm (implicit cast) sang một kiểu chung, nếu không PostgreSQL sẽ báo lỗi.

-- Lỗi: không thể kết hợp integer và text trực tiếp
SELECT COALESCE(123, 'hello');

-- Đúng: ép kiểu tường minh
SELECT COALESCE(123::text, 'hello');
7.3 Index và COALESCE

Sử dụng COALESCE trong mệnh đề WHERE có thể vô hiệu hóa index trên cột đó. Giải pháp: tạo Expression Index:

CREATE INDEX idx_department_coalesce
ON employees (COALESCE(department, 'Không xác định'));

8. Ví dụ nâng cao: Dùng với JSON và JSONB


SELECT
    id,
    COALESCE(
        data ->> 'display_name',
        data ->> 'username',
        'anonymous'
    ) AS user_label
FROM user_profiles;

9. Tổng kết

COALESCE là một trong những hàm thiết yếu nhất trong PostgreSQL. Nắm vững nó giúp bạn:

  •  Xử lý NULL an toàn và nhất quán.
  •  Viết truy vấn ngắn gọn, dễ đọc hơn CASE WHEN.
  •  Xây dựng logic fallback linh hoạt.
  •  Tránh lỗi tính toán do NULL lan truyền.

Mẹo của DBA: Khi thiết kế schema, hãy tự hỏi: "Cột này có thể NULL không? Nếu có, giá trị mặc định hiển thị là gì?" — câu trả lời thường dẫn đến một COALESCE.

Chúc các bạn thành công !