CodeGym /Các khóa học /SQL SELF /Hàm GREATEST() và LEAST() cùng với NULL

Hàm GREATEST() và LEAST() cùng với NULL

SQL SELF
Mức độ , Bài học
Có sẵn

Hôm nay tụi mình sẽ đào sâu vào một chủ đề khá đặc biệt nhưng lại rất quan trọng: hàm GREATEST()LEAST(). Bạn sẽ biết cách tìm giá trị lớn nhất và nhỏ nhất từ nhiều cột, và quan trọng nhất là NULL ảnh hưởng thế nào đến kết quả của chúng.

Nếu bạn từng đi tìm thứ quan trọng nhất trong đời mình (tình yêu, công việc mơ ước hay công thức pizza ngon nhất), bạn sẽ hiểu ngay tại sao cần dùng GREATEST()LEAST(). Hai hàm này giúp bạn tìm ra giá trị lớn nhất hoặc nhỏ nhất trong một danh sách thứ gì đó. Chỉ khác là thay vì pizza, bạn làm việc với số, ngày tháng, chuỗi và các kiểu dữ liệu khác trong PostgreSQL.

GREATEST()

GREATEST() trả về giá trị lớn nhất trong tập giá trị truyền vào.

Cú pháp:

GREATEST(value1, value2, ..., valueN)

LEAST()

LEAST() làm điều ngược lại: nó tìm giá trị nhỏ nhất.

Cú pháp:

LEAST(value1, value2, ..., valueN)

Ví dụ:

Giả sử tụi mình có bảng students_scores, nơi lưu điểm của sinh viên cho ba kỳ thi:

student_id exam_1 exam_2 exam_3
1 85 90 82
2 NULL 76 89
3 94 NULL 88

Cách dùng GREATEST()LEAST():

SELECT
    student_id,
    GREATEST(exam_1, exam_2, exam_3) AS highest_score,
    LEAST(exam_1, exam_2, exam_3) AS lowest_score
FROM students_scores;

Kết quả:

student_id highest_score lowest_score
1 90 82
2 89 NULL
3 94 NULL

NULL ảnh hưởng thế nào đến GREATEST()LEAST()

Giờ đến phần thú vị nhất. Trong bảng có thể xuất hiện cả giá trị NULL. Như tụi mình đã biết, NULL là một thứ bí ẩn, đại diện cho dữ liệu không tồn tại hoặc giá trị chưa biết. Cùng xem điều gì xảy ra nếu NULL xuất hiện trong các hàm GREATEST()LEAST() trong PostgreSQL nhé.

Hành vi của NULL:

Trong PostgreSQL, các hàm GREATEST()LEAST() có hành vi đặc biệt: chúng sẽ bỏ qua giá trị NULL khi tìm giá trị lớn nhất hoặc nhỏ nhất trong các tham số truyền vào. Lưu ý: Trường hợp duy nhất mà hai hàm này trả về NULL là khi tất cả các tham số đều là NULL.

Ví dụ:

SELECT
    GREATEST(10, 20, NULL, 5) AS greatest_value,
    LEAST(10, 20, NULL, 5) AS least_value;

Kết quả:

greatest_value least_value
20 5

Nhìn nè, NULL đã bị bỏ qua, và các hàm trả về giá trị lớn nhất và nhỏ nhất trong số các giá trị còn lại (10, 20, 5).

Còn đây là ví dụ khi tất cả tham số đều là NULL:

Ví dụ:

SELECT
    GREATEST(NULL, NULL) AS greatest_nulls,
    LEAST(NULL, NULL) AS least_nulls;

Kết quả:

greatest_nulls least_nulls
NULL NULL

Làm sao tránh rắc rối với NULL?

Dù PostgreSQL mặc định bỏ qua NULL, đôi khi bạn lại muốn hành vi khác. Ví dụ, bạn muốn NULL được coi như một giá trị cụ thể (như 0 hoặc một giá trị mặc định khác) khi xác định giá trị lớn nhất/nhỏ nhất. Lúc này, bạn có thể dùng hàm COALESCE().

Hàm COALESCE(arg1, arg2, ...) trả về tham số đầu tiên không phải NULL trong danh sách. Nhờ đó, bạn có thể thay thế NULL bằng một giá trị hợp lý trước khi truyền vào GREATEST() hoặc LEAST().

Ví dụ 1: Thay NULL bằng 0

Giả sử bạn muốn coi điểm thiếu (NULL) là 0. Ta dùng COALESCE() để thay thế giá trị mặc định.

Bảng gốc của tụi mình:

student_id exam_1 exam_2 exam_3
1 90 85 82
2 NULL 89 NULL
3 NULL NULL 94

Truy vấn:

SELECT
    student_id,
    GREATEST(
        COALESCE(exam_1, 0), 
        COALESCE(exam_2, 0), 
        COALESCE(exam_3, 0)
    ) AS highest_score,
    LEAST(
        COALESCE(exam_1, 0), 
        COALESCE(exam_2, 0), 
        COALESCE(exam_3, 0)
    ) AS lowest_score
FROM students_scores;

Kết quả:

student_id highest_score lowest_score
1 90 82
2 89 0
3 94 0

Ví dụ 2: Thay NULL bằng giá trị từ cột khác

Đôi khi thay vì một giá trị cố định (như 0), bạn lại muốn lấy giá trị từ cột khác. Ví dụ, nếu exam_3 bị thiếu, bạn muốn dùng giá trị từ exam_1.

SELECT
    student_id,
    GREATEST(
        exam_1, 
        exam_2, 
        COALESCE(exam_3, exam_1)
    ) AS highest_score
FROM students_scores;

Giả sử bảng như sau:

student_id exam_1 exam_2 exam_3
1 90 85 82
2 NULL 89 NULL
3 70 NULL NULL

Kết quả truy vấn:

student_id highest_score
1 90
2 89
3 70

Case thực tế

Case 1: Tìm giảm giá lớn nhất

order_id discount_1 discount_2 discount_3
101 5 10 7
102 NULL 3 8
103 15 NULL NULL
104 NULL NULL NULL

Bạn đang làm việc với bảng orders, mỗi đơn hàng có thể có ba loại giảm giá khác nhau. Nhiệm vụ là tìm giảm giá lớn nhất cho từng đơn hàng.

SELECT
    order_id,
    GREATEST(discount_1, discount_2, discount_3) AS max_discount
FROM orders;

Kết quả:

order_id max_discount
101 10
102 8
103 15
104 NULL

Case 2: Tìm giá thấp nhất của sản phẩm

Trong bảng products lưu giá sản phẩm ở ba loại tiền (USD, EUR, GBP). Nhiệm vụ của bạn là tìm giá thấp nhất cho từng sản phẩm.

product_id price_usd price_eur price_gbp
1 100 95 80
2 NULL 150 140
3 200 NULL NULL
4 NULL NULL NULL
SELECT
    product_id,
    LEAST(price_usd, price_eur, price_gbp) AS lowest_price
FROM products;
product_id lowest_price
1 80
2 140
3 200
4 NULL

Nếu tất cả giá đều NULL, kết quả cũng là NULL

Lỗi phổ biến khi dùng GREATEST()LEAST()

Lỗi 1: Kết quả không như mong đợi do NULL.

Ở trên tụi mình đã nói kỹ về việc NULL ảnh hưởng thế nào đến GREATEST()LEAST() trong PostgreSQL. Lỗi phổ biến là nhiều bạn quen với cách NULL hoạt động ở các hệ quản trị khác (nơi chỉ cần một NULL là cả kết quả thành NULL), nên cũng nghĩ PostgreSQL sẽ như vậy.

Lỗi xuất hiện thế nào: Bạn có thể nghĩ rằng nếu danh sách tham số có NULL, hàm sẽ luôn trả về NULL. Vì vậy, bạn có thể dùng COALESCE() cho tất cả tham số mà không cần thiết, làm truy vấn phức tạp và chậm hơn, trong khi thực ra NULL chỉ bị bỏ qua thôi.

Lỗi 2: Dùng GREATEST()LEAST() với kiểu dữ liệu không tương thích.

Hai hàm GREATEST()LEAST() chỉ nên dùng để so sánh các giá trị cùng kiểu dữ liệu hoặc các kiểu có thể tự động chuyển đổi cho nhau. Nếu bạn thử so sánh các kiểu hoàn toàn khác nhau, sẽ bị lỗi ngay.

Lỗi xuất hiện thế nào: Bạn sẽ nhận được thông báo lỗi về việc kiểu dữ liệu không tương thích.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION