So sánh số
Bạn sẽ học được
- Dùng sáu toán tử so sánh số và biết khi nào dùng
<>thay cho!=. - Viết literal số đúng cách, không dấu chấm ngăn cách và không dấu nháy.
- Dùng
BETWEENđúng với biên trên và biên dưới. - Kiểm tra một điều kiện số bằng cách đối chiếu với dữ liệu gốc.
- Nhận ra các lỗi khiến phép so sánh chạy được nhưng trả sai kết quả.
Khái niệm cốt lõi
So sánh số là dạng lọc cơ bản nhất. Có sáu toán tử:
| Toán tử | Nghĩa | Ví dụ trên products.price |
|---|---|---|
= | bằng | price = 890000 |
<> | khác | price <> 890000 |
> | lớn hơn | price > 1000000 |
>= | lớn hơn hoặc bằng | price >= 1000000 |
< | nhỏ hơn | price < 300000 |
<= | nhỏ hơn hoặc bằng | price <= 300000 |
PostgreSQL cũng chấp nhận != như một cách viết khác của <>. Cả hai cho cùng kết quả. Tuy vậy, <> là chuẩn SQL và xuất hiện trong hầu hết tài liệu, nên hãy chọn một kiểu và giữ nhất quán — thường là <>.
Literal số viết trực tiếp, không có dấu nháy và không có dấu chấm ngăn cách hàng nghìn:
-- Đúng
SELECT name FROM products WHERE price >= 1000000;
-- Sai: Postgres hiểu '1.000.000' là chuỗi
SELECT name FROM products WHERE price >= '1.000.000';Câu thứ hai có thể báo lỗi hoặc trả kết quả sai tùy ngữ cảnh, vì '1.000.000' không phải một số hợp lệ theo định dạng PostgreSQL. Đây là lỗi rất Việt Nam: chúng ta quen viết 1.000.000 với dấu chấm, còn SQL dùng dấu chấm làm dấu thập phân. Trong SQL, một triệu là 1000000, còn 1.000000 là một phẩy không.
BETWEEN a AND b là cách viết gọn cho >= a AND <= b. Cả hai biên đều bao gồm:
SELECT name, price
FROM products
WHERE price BETWEEN 300000 AND 900000;Tương đương:
SELECT name, price
FROM products
WHERE price >= 300000 AND price <= 900000;Có hai cái bẫy. Thứ nhất, đặt ngược biên — BETWEEN 900000 AND 300000 — trả về 0 dòng chứ không báo lỗi, vì không số nào vừa lớn hơn 900000 vừa nhỏ hơn 300000. Thứ hai, quên rằng biên trên bao gồm: nếu muốn "dưới 900000" thì phải viết < 900000, không dùng BETWEEN.
Với số thực (numeric, double precision), so sánh bằng = có thể gây bất ngờ vì sai số biểu diễn. Với cột price numeric(12,2) trong dữ liệu này thì an toàn, nhưng khi tính toán với double precision, hãy so sánh trong một khoảng thay vì bằng tuyệt đối. Đây là lý do các hệ thống tài chính dùng numeric thay vì số thực.
Cuối cùng, số và NULL không so sánh được bằng các toán tử trên. price = NULL trả về unknown, không phải true, nên không dòng nào được chọn. Muốn kiểm tra NULL, dùng IS NULL. Chủ đề này có bài riêng ở cuối chương, nhưng cần biết trước để không ngạc nhiên khi thấy kết quả rỗng.
Ví dụ chạy được
Bảng products có 9 sản phẩm với giá từ 180.000 đến 1.690.000. Lấy các sản phẩm từ 500.000 trở lên:
SELECT id, name, price
FROM products
WHERE price >= 500000
ORDER BY price;Ba dòng:
| id | name | price |
|---|---|---|
| 1 | Tai nghe Bluetooth | 890000 |
| 2 | Bàn phím cơ | 1250000 |
| 3 | Nồi chiên không dầu | 1690000 |
Đổi chiều so sánh, lấy các sản phẩm dưới 500.000:
SELECT name, price
FROM products
WHERE price < 500000
ORDER BY price;Sáu dòng: Sách SQL thực chiến (180000), Áo thun cotton (250000), Đèn bàn LED (290000), Bình giữ nhiệt (320000), Giá kê laptop (390000), Chuột không dây (450000).
Ba cộng sáu bằng chín, đúng bằng số sản phẩm. Đây là phép kiểm tra quen thuộc: hai điều kiện bù trừ (>= 500000 và < 500000) phải phủ toàn bộ bảng. Nếu thiếu một sản phẩm, có thể bạn đã dùng > 500000 ở một bên và > 500000 ở bên kia, để lọt đúng mức 500.000.
Dùng BETWEEN cho khoảng giá trung bình:
SELECT name, price
FROM products
WHERE price BETWEEN 300000 AND 900000
ORDER BY price;Bốn dòng: Bình giữ nhiệt (320000), Giá kê laptop (390000), Chuột không dây (450000), Tai nghe Bluetooth (890000). Sản phẩm 1.250.000 và 1.690.000 nằm ngoài khoảng; sản phẩm 290.000 cũng ngoài vì nhỏ hơn biên dưới 10.000.
Một ví dụ trên cột số nguyên, stock:
SELECT name, stock
FROM products
WHERE stock >= 10
ORDER BY stock DESC;Sáu dòng: Áo thun cotton (40), Sách SQL thực chiến (30), Tai nghe Bluetooth (25), Chuột không dây (18), Đèn bàn LED (12), Bàn phím cơ (10). Bàn phím cơ đúng bằng 10 nên được chọn — >= bao gồm biên. Bình giữ nhiệt có stock = 0 bị loại; ba sản phẩm còn lại có tồn kho dưới 10 cũng bị loại.
Một thói quen tốt: khi viết điều kiện biên, luôn tự hỏi "giá trị đúng bằng biên thì sao?". Với >= và <=, nó được chọn; với > và <, nó bị loại. Chỉ một ký tự khác nhau nhưng thay đổi kết quả, và trong báo cáo kinh doanh, một sản phẩm bị lọt có thể làm sai toàn bộ doanh thu.
Thực hành
- Viết truy vấn lấy các sản phẩm có giá trên 1.000.000. Kết quả phải là hai dòng (Bàn phím cơ, Nồi chiên không dầu). Sau đó đổi thành
>= 1000000và xác nhận kết quả không đổi — vì không sản phẩm nào đúng bằng 1.000.000. - Lấy các sản phẩm còn hàng bằng
stock <> 0. Kết quả tám dòng. Thửstock > 0và so sánh: với dữ liệu này hai cách cho cùng kết quả, nhưng> 0rõ ý hơn khi nói về "còn hàng". - Viết truy vấn lấy các đơn có
idtừ 5 đến 10 bằngBETWEEN. Kết quả sáu dòng. Đổi thànhid > 5 AND id < 10và đếm lại: còn bốn dòng, vì hai biên bị loại. - Tự đặt một khoảng giá, dự đoán danh sách sản phẩm, rồi chạy để đối chiếu. Làm ba lần với ba khoảng khác nhau; đây là cách luyện đọc dữ liệu nhanh.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
invalid input syntax for type numeric: "1.000.000" | Dùng dấu chấm ngăn cách hàng nghìn | Viết 1000000, không nháy |
| Truy vấn trả 0 dòng dù khoảng có dữ liệu | Đặt ngược biên trong BETWEEN | Đặt biên nhỏ trước, lớn sau |
| Kết quả thiếu đúng giá trị biên | Dùng >/< thay vì >=/<= | Thêm dấu = nếu muốn bao gồm biên |
So sánh với NULL không trả dòng nào | = NULL luôn là unknown | Dùng IS NULL hoặc IS NOT NULL |
operator does not exist: numeric = text | So sánh cột số với chuỗi không chuyển được | Bỏ dấu nháy quanh số |
Lỗi đầu tiên đặc biệt phổ biến với người mới vì thói quen viết số tiếng Việt. Hãy nhớ: trong SQL, dấu chấm là dấu thập phân, dấu phẩy ngăn cách đối số hàm. Không có dấu phân cách hàng nghìn.
Lỗi cuối cùng ít gặp hơn nhưng đáng biết: PostgreSQL có thể báo operator does not exist khi hai bên không cùng kiểu và không có chuyển đổi ngầm. Đây là tín hiệu tốt — nó buộc bạn viết đúng kiểu thay vì để cơ sở dữ liệu đoán.
Tóm tắt
- Sáu toán tử:
=,<>,>,>=,<,<=;!=cũng chạy nhưng<>là chuẩn. - Literal số không nháy, không dấu chấm ngăn cách hàng nghìn.
BETWEEN a AND bbao gồm cả hai biên và tương đương>= a AND <= b.- Hai điều kiện bù trừ phải phủ toàn bộ bảng — dùng phép đếm để kiểm tra.
NULLkhông so sánh được bằng toán tử; dùngIS NULL.
Dùng ← → để chuyển bài