Masalah pembulatan desimal otomatis

11

Pertanyaannya relatif sederhana. Saya perlu menghitung 3 kolom di mana hasil pertengahan adalah desimal besar, dan saya mengalami masalah di awal dengan SQL Server pada dasarnya membulatkan desimal terlepas dari pemain / konversi.

Sebagai contoh, mari kita lakukan pembagian sederhana sebagai 1234/1233. Kalkulator akan menghasilkan 1.00081103000811. Tetapi ketika saya melakukan ini di SQL Server, kami mendapatkan yang berikut:

-- Result: rounded at 1.000811000... with trailing zeroes up until the 37 precision
SELECT CAST(CAST(1234 AS DEC(38,34))/CAST(1233 AS DEC(38,34)) AS DEC(38,37))

-- Result: rounded at 1.000811
SELECT CONVERT(DECIMAL(38,32), 1234)/CONVERT(DECIMAL(38,32),1233)

-- Correct result at 1,00081103000811
-- But this requires the zeroes to be put in manually when you don't
-- even know the precision of the end result
SELECT 1234.0/1233.00000000000000

Mengapa pembulatan otomatis ini terjadi? Dan apa cara terbaik untuk menghitung nilai desimal yang sangat panjang ketika Anda tidak dapat memastikan seberapa besar angka (bagian int atau dec) akan, karena tabel dapat berisi berbagai nilai yang berbeda?

Terima kasih!

Kahn
sumber

Jawaban:

17

tl; dr

Jangan lakukan perhitungan dalam bahasa SQL

Lebih lama

Skala dan ketepatan hasil didefinisikan dengan baik di sini di MSDN . Itu tidak intuitif, sungguh. Namun, secara sederhana, presisi hilang ketika skala input tinggi karena skala hasil harus turun ke 38 dengan penurunan presisi yang cocok.

Untuk mengkonfirmasi hal-hal

  • CAST ekstra Anda dalam contoh pertama cukup tambahkan angka nol
  • Pemotongan terjadi sesuai tautan MSDN saya (contoh 2)
  • Contoh ke-3 dengan konstanta menyiratkan nilai desimal yang cukup (5,1) dan 18,14).
    Ini berarti skala hasil dan ketelitian tidak memiliki pemotongan (lihat pukulan)

Lebih lanjut tentang kasus 1 dan 3 ..

Skala hasil untuk suatu divisi adalah max(6, s1 + p2 + 1):

  • Contoh pertama, ini adalah 77 yang turun menjadi 38. Presisi dipaksa turun dengan cara yang sama, tunduk pada minimum 6 (lihat ini )
  • Contoh ketiga, ini adalah 24 sehingga presisi tidak perlu disesuaikan

Anda memiliki beberapa opsi

  • hitung dalam kode klien mis .net
  • gunakan fungsi CLR untuk melakukan perhitungan .net
  • hidup dengan hilangnya keakuratan
  • gunakan float dan hidup dengan 15 angka penting sebagai yang terbaik

Akhirnya, lihat ini di SO /programming/423925/t-sql-decimal-division-accuracy/424052#424052

gbn
sumber
1

Tidak yakin apakah ini membantu tetapi bagi saya kolom tabel temp saya disetel ke desimal, saya melewati konversi (desimal (15,2), 0,65) dari sisipan ke temp_table. Ini pembulatan otomatis, saya mengubah tipe kolom menjadi desimal (16,2) untuk mencocokkan dengan apa yang sedang dilewati. Tabel sekarang menyimpan 0,65.

natur3
sumber
1

Saya harus melakukan pekerjaan di sekitar. Inilah yang saya lakukan:

-----------------------------------
DECLARE @DENIED INT  = 33443
DECLARE @PAID INT = 148353
DECLARE @PCT Decimal (6,2)

SET @PCT = (@DENIED * 100.00 / @PAID)  -- Instead of dividing by 100, I included decimals

SELECT
@DENIED AS DEN
,@PAID AS PAID
,@PCT AS PCT

Hasil:

DEN PAID    PCT
-----   ----    -----
33443   148353  22.54   -- Instead of 22.00

Semoga ini membantu.

Manoj C
sumber