Fungsi ROUND membulatkan nilai input berdasarkan jumlah tempat desimal yang Anda tentukan. Namun, saat membulatkan literal numerik, hasil yang diperoleh mungkin tidak sesuai ekspektasi — misalnya, round(0.25375, 4) mengembalikan 0.2537, bukan 0.2538 seperti yang diharapkan.
Penyebab masalah ini
Sebelum mengeksekusi ROUND, MaxCompute mengonversi literal numerik ke tipe data DOUBLE. DOUBLE merupakan tipe floating-point yang tidak dapat merepresentasikan semua nilai desimal secara eksak. Selama konversi tersebut, 0.25375 berubah menjadi 0.2536999999..., yang kemudian dibulatkan ke bawah menjadi 0.2537.
Masalah ini hanya terjadi pada literal numerik yang diberikan langsung ke fungsi. Saat ROUND memproses data dari kolom tabel, fungsi tersebut membaca tipe data aktual kolom tersebut, sehingga masalah presisi tidak muncul.
Solusi
Lakukan casting nilai input ke DECIMAL sebelum meneruskannya ke ROUND. Berbeda dengan DOUBLE, DECIMAL menyimpan nilai secara eksak, sehingga konversi tidak menyebabkan kehilangan presisi.
Hasil eksak bergantung pada apakah mode Hive-compatible diaktifkan atau tidak.
Dengan set odps.sql.hive.compatible=false;
Baik decimal (tanpa presisi yang ditentukan) maupun decimal(20,5) menghasilkan nilai yang benar:
select round(cast(0.25375 as decimal), 4);
-- Returns: 0.2538
select round(cast(0.25375 as decimal(20,5)), 4);
-- Returns: 0.2538Dengan set odps.sql.hive.compatible=true;
Gunakan decimal(p,s) dengan presisi dan skala eksplisit. Penggunaan decimal tanpa spesifikasi presisi akan mengembalikan 0 dalam mode Hive-compatible:
select round(cast(0.25375 as decimal), 4);
-- Returns: 0
select round(cast(0.25375 as decimal(20,5)), 4);
-- Returns: 0.2538Dalam mode Hive-compatible, selalu gunakan decimal(p,s) dengan presisi dan skala eksplisit untuk memperoleh hasil yang diharapkan.