Saya menjalankan SQL Server 2012
SELECT
0.15 * 30 / 360,
0.15 / 360 * 30
Hasil:
0.012500,
0.012480
Yang ini bahkan lebih membingungkan bagi saya:
DECLARE @N INT = 360
DECLARE @I DECIMAL(38,26) = 0.15 * 30 / 360
DECLARE @C DECIMAL(38,26) = 1000000
SELECT @C * @I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 )
SELECT @C * (@I * POWER(1 + @I, @N) / ( POWER(1 + @I, @N) - 1 ) )
Pilihan pertama memberi saya hasil yang benar: 12644.44022 Yang kedua memotong hasilnya: 12644.00000
sql-server
sql-server-2012
t-sql
decimal
cpacheco
sumber
sumber
Jawaban:
Menentukan presisi dan skala yang dihasilkan dari ekspresi adalah sarang tikus dan saya tidak berpikir ada yang mengerti aturan yang tepat dalam setiap skenario, terutama ketika mencampur desimal (atau float!) Dan int. Lihat jawaban ini oleh gbn .
Tentu saja Anda dapat menyesuaikan ekspresi untuk memberikan apa yang Anda inginkan dengan membuat konversi eksplisit yang jauh lebih banyak. Ini mungkin berlebihan tetapi:
Tidak ada hasil yang dibulatkan secara salah karena matematika floating point yang rusak atau presisi / skala yang salah.
sumber
Seperti yang disebutkan Aaron Bertrand, ekspresi sangat sulit diprediksi.
Jika Anda berani pergi ke sana, Anda bisa mencoba mendapatkan wawasan menggunakan cuplikan berikut:
Ini hasilnya:
sumber
Meskipun jawaban yang sangat baik sudah ditambahkan ke pertanyaan ini, ada urutan prioritas yang didefinisikan secara eksplisit untuk konversi tipe data dalam SQL Server.
Ketika seorang operator menggabungkan dua ekspresi dari tipe data yang berbeda, aturan untuk presedensi tipe data menentukan bahwa tipe data dengan presedensi yang lebih rendah dikonversi ke tipe data dengan prioritas yang lebih tinggi. Jika konversi itu bukan konversi tersirat yang didukung, kesalahan dikembalikan. Ketika kedua ekspresi operan memiliki tipe data yang sama, hasil operasi memiliki tipe data tersebut.
SQL Server menggunakan urutan prioritas berikut untuk tipe data:
Jadi, misalnya, jika Anda
SELECT 0.5 * 1
(mengalikan desimal oleh int) Anda mendapatkan hasil yang dikonversi ke nilai desimal, karenadecimal
ini lebih tinggi diutamakan daripadaint
tipe data.Lihat http://msdn.microsoft.com/en-us/library/ms190309.aspx untuk rincian lebih lanjut.
Setelah mengatakan semua itu, mungkin
SELECT @C * (@I * POWER(1 + @I, @N) / (POWER(1 + @I, @N) - 1 ));
harus mengembalikan nilai desimal, karena praktis semua input adalah desimal. Menariknya, Anda dapat memaksakan hasil yang benar dengan memodifikasi ituSELECT
untuk:Ini mengembalikan:
Saya bingung menjelaskan bagaimana itu membuat perbedaan, meskipun jelas itu terjadi . Dugaan saya adalah
1E0
(float eksplisit) dalamPOWER(
fungsi memaksa SQL Server untuk membuat pilihan berbeda pada tipe output untukPOWER
fungsi. Jika anggapan saya benar, itu akan menunjukkan kemungkinan bug dalamPOWER
fungsi, karena dokumentasi menyatakan input pertamaPOWER()
adalah float, atau angka yang secara implisit dapat dikonversi menjadi float.sumber
Apakah Anda terbiasa dengan
SELECT .. INTO
sintaks ? Ini adalah trik yang berguna untuk mendekonstruksi situasi seperti ini karena membuat tabel dengan cepat hanya dengan tipe data yang tepat untukSELECT
daftar yang diberikan .Anda dapat memecah perhitungan Anda menjadi langkah-langkah penyusunnya, menerapkan aturan prioritas SQL Server saat Anda mulai, untuk melihat bagaimana definisi berubah. Beginilah contoh pertama Anda akan terlihat:
Ini hasilnya:
sumber
(1+1)
dan2
tipeint
tetapi pertanyaan ini memiliki contoh di mana mereka akhirnya menghasilkan hasil yang diketik berbeda.