Bạn có một đơn đã thanh toán trên tổng bốn đơn, nhưng API trả tỷ lệ bằng 0. Việc làm tròn ở giao diện chưa chắc là nguyên nhân. Nếu phép chia được thực hiện giữa hai số nguyên, phần thập phân có thể đã bị loại ngay trong database. Ép kết quả ấy sang kiểu số thực sau đó không lấy lại thông tin đã mất.
Bài cập nhật ngày 09/11/2026, chạy các truy vấn trên SQLite 3.54.0 và đối chiếu tài liệu PostgreSQL 17. Chưa chạy PostgreSQL server, ORM hoặc benchmark. Ví dụ nhận sẵn số lượng, tập trung vào phép chia; nó không xây dựng truy vấn đếm đơn theo trạng thái.
Nhìn kiểu ở ngay phép toán đầu tiên
Chạy truy vấn này trong SQLite:
SELECT
1 / 4 AS integer_ratio,
CAST(1 / 4 AS REAL) AS cast_too_late,
CAST(1 AS REAL) / 4 AS cast_before_division,
1.0 / 4 AS real_ratio;
Kết quả lần lượt là 0, 0.0, 0.25, 0.25. SQLite expressions mô tả phép toán dùng số nguyên khi hai toán hạng là số nguyên và không tràn. Vì vậy, CAST của biểu thức 1 / 4 chỉ nhận được số 0 đã tính xong.
Đặt CAST ở tử số làm phép chia nhận một toán hạng REAL ngay từ đầu. Hằng số 1.0 cũng tạo khác biệt về kiểu so với 1. Khi đọc query có nhiều tầng expression, hãy xác định phép toán nào xảy ra trước thay vì chỉ nhìn kiểu của cột kết quả cuối.
Xử lý rõ trường hợp chưa có mẫu số
Tỷ lệ không xác định khi tổng số mẫu bằng 0. Ví dụ dưới chọn trả NULL cho tình huống đó:
WITH counts(paid, total) AS (
VALUES (1, 4), (0, 4), (0, 0)
)
SELECT
paid,
total,
CAST(paid AS REAL) / NULLIF(total, 0) AS paid_ratio
FROM counts
ORDER BY total DESC, paid DESC;
Ba tỷ lệ theo thứ tự là 0.25, 0.0, NULL. NULLIF của SQLite trả NULL khi hai đối số bằng nhau, nên mẫu số 0 được chuyển thành NULL trước phép chia. Dòng có tổng 4 và paid 0 vẫn có tỷ lệ bằng 0; nó khác dòng chưa có đơn nào để tính.
Nếu API trả JSON, hãy giữ quyết định này nhất quán trong hợp đồng: NULL có thể mang nghĩa “chưa đủ dữ liệu”. Việc đổi nó thành 0 để vẽ biểu đồ là một lựa chọn sản phẩm cần được nêu rõ, vì người đọc có thể hiểu 0 là đã quan sát nhưng không có đơn paid.
Tỷ lệ và phần trăm là hai thang hiển thị
SELECT
CAST(1 AS REAL) / NULLIF(4, 0) AS ratio,
100.0 * 1 / NULLIF(4, 0) AS percent;
Kết quả là 0.25 và 25.0. Chọn một thang để lưu hoặc truyền qua API và ghi rõ tên trường. Nếu backend đã nhân 100 mà frontend tiếp tục nhân nữa, phần trăm sẽ sai dù phép chia có kiểu đúng. Không suy ra thang đo chỉ từ việc cột chứa số thực.
Tránh viết (paid / total) * 100.0 khi paid và total vẫn là số nguyên, vì lỗi có thể xuất hiện trước phép nhân. Cũng đừng chỉ kiểm tra trường hợp hai số chia hết: 4 / 4 có thể che mất lỗi mà 1 / 4 sẽ phát hiện.
Đối chiếu khi dự án dùng PostgreSQL
PostgreSQL 17 mathematical operators cũng phân biệt phép chia số nguyên và số có phần thập phân. Nếu cần số học decimal trong PostgreSQL, hãy đọc quy tắc kiểu numeric của hệ thống đó và ép kiểu toán hạng phù hợp; không sao chép tên REAL rồi mặc định độ chính xác giống mọi database.
PostgreSQL NULLIF mô tả cùng ý tưởng đổi một giá trị bằng giá trị so sánh thành NULL. Phần đối chiếu này dựa trên tài liệu, không phải kết quả chạy query trên PostgreSQL trong bài.
Kiểm tra miền dữ liệu và giới hạn
Thêm ca một phần tư, không paid trên tổng dương, tổng bằng 0 và paid bằng total. Rà thêm đầu vào NULL và kiểu thực tế của cột hoặc parameter từ driver. Ví dụ giả định hai số đếm là số nguyên không âm và paid không vượt total; phép CAST không tự xác minh các điều kiện nghiệp vụ đó.
SQLite REAL dùng số thực nhị phân, nên đây không phải mẫu thiết kế cho tính tiền cần độ chính xác decimal. Với tỷ lệ báo cáo, kiểm tra đầu ra bằng sai số phù hợp, còn việc làm tròn để hiển thị nên được quyết định riêng. Bước sửa đầu tiên vẫn là ép kiểu ở đúng toán hạng trước khi phép chia diễn ra.


