L'operazione decimale di SQL Server non è accurata
Quando eseguo questa semplice operazione in SQL server:
Select 800.0 /30.0
Ottengo il valore 26.666666, dove anche se arrotonda per 6 cifre dovrebbe essere 26.666667. Come posso fare in modo che il calcolo sia accurato? Ho provato a cercarlo online e ho trovato una soluzione in cui eseguo il cast di ogni operando con un decimale ad alta precisione prima dell'operazione, ma questo non sarà conveniente per me perché ho molti calcoli lunghi e complessi. penso che ci debba essere una soluzione migliore.
Risposte
Quando si utilizza una divisione, in SQL Server, qualsiasi cifra dopo la scala risultante viene troncata, non arrotondata. Per la tua espressione hai un decimal(4,1)e a decimal(3,1), che si traduce in a decimal(10,6):
Precision = p1 - s1 + s2 + max(6, s1 + p2 + 1)
Scale = max(6, s1 + p2 + 1)
Di conseguenza, 26.66666666666666~viene troncato a 26.666666.
È possibile aggirare questo problema aumentando la dimensione della precisione e della scala, quindi CONVERTtornare alla precisione e alla scala richieste. Ad esempio, aumentare la precisione e la scala di decimal(3,1)a decimal(5,2)e riconvertire in decimal(10,6):
SELECT CONVERT(decimal(10,6),800.0 / CONVERT(decimal(5,3),30.0));
Questo ritorna 26.666667.
Questo potrebbe essere utile:
Usa ROUND (Transact-SQL)
SELECT ROUND(800.0 /30.0, 5) AS RoundValue;
Risultato:
RoundValue
26.666670
Credo che sia perché SQL Server prende i tuoi numeri come decimalvalori (che sono esatti, ad esempio, 6.6666 e 6.6667 significa esattamente quei valori, non 6 e due terzi) piuttosto che floatvalori (che possono funzionare con numeri approssimativi).
Se lo lanci / converti esplicitamente in floata all'inizio, dovresti ottenere che i tuoi calcoli funzionino senza intoppi.
Ecco alcuni esempi per dimostrare la differenza tra int, decimale floatcalcoli
- Dividendo 20 per 3
- Dividendo 20 per 3, quindi moltiplicando di nuovo per 3 (che matematicamente dovrebbe essere 20).
SELECT (20/3) AS int_calc,
(20/3) * 3 AS int_calc_x3,
(CAST(20 AS decimal(10,3)) /3) AS dec_calc,
(CAST(20 AS decimal(10,3)) /3) * 3 AS dec_calc_x3,
(CAST(20 AS float) /3) AS float_calc,
(CAST(20 AS float) /3) * 3 AS float_calc_x3
con i seguenti risultati
int_calc int_calc_x3 dec_calc dec_calc_x3 float_calc float_calc_x3
6 18 6.666666 19.999998 6.66666666666667 20
Nel tuo caso, puoi usare
Select CAST(800.0 AS float) /30.0
che si traduce in 26.6666666666667
Nota se moltiplichi per 30, otterrai il risultato corretto, ad es.
Select (CAST(800.0 AS float) /30.0) * 30
risultati in 800. Le soluzioni che si occupano di decimali non lo avranno.
Nota anche che una volta che lo hai come float, dovrebbe rimanere un float fino a quando non viene riconvertito in un decimale o in un int in qualche modo (ad esempio, salvato in una tabella come int). Così...
SELECT A.Num / 30
FROM (Select ((CAST(800.0 AS float) /30.0) * 30) AS Num) AS A
risulterà comunque in 26.6666666666667
Si spera che questo ti aiuti nei tuoi calcoli lunghi e complessi.