5

Il debug di un codice SQL relativo alle finanze ha trovato uno strano problema con la precisione matematica numerica (24,8).Perdita di precisione numerica del server SQL 2005

Eseguire la seguente query sul MSSQL si otterrebbe un + B risultato dell'espressione * C per essere 0,123457

SELEZIONE A, B, C, A + B * C DA ( SELEZIONA CAST (0.12345678 come numerico (24,8)) COME, CAST (0 come numerico (24,8)) AS B, CAST (500 come numerico (24,8)) AS C ) T

Così abbiamo perso 2 simboli significativi. Cercando di risolverlo in modi diversi, ho ottenuto che la conversione del risultato della moltiplicazione intermedia (che è zero!) In numerica (24,8) funzionasse correttamente.

E finalmente una soluzione. Ma ancora ho una domanda: perché MSSQL si comporta in questo modo e quali conversioni di tipo si sono verificate nel mio esempio?

risposta

7

Proprio come l'aggiunta del tipo float è imprecisa, la moltiplicazione dei tipi di decimali può essere inaccurata (o causare inaccuratezza) se si supera la precisione. Vedi Data Type Conversion e decimal and numeric.

Dal momento che moltiplicato NUMERIC(24,8) e NUMERIC(24,8), e SQL Server controllerà solo il tipo non il contenuto, probabilmente cercherà di salvare i potenziali 16 cifre non decimali (24 - 8), quando non è possibile salvare tutte le 48 cifre di precisione (il massimo è 38). Combinandone due, ottieni 32 cifre non decimali, che ti lasciano con solo 6 cifre decimali (38 - 32).

Così la query originale

SELECT A, B, C, A + B * C 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C) T 

riduce a

SELECT A, B, C, A + D 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C, 
    CAST(0 AS NUMERIC(38,6)) AS D) T 

Ancora, tra NUMERIC(24,8) e NUMERIC(38,6), SQL Server tenterà di salvare i potenziali 32 cifre non decimali, così A + D riduce a

SELECT CAST(0.12345678 AS NUMERIC(38,6)) 

che gi Vs you 0.123457 dopo l'arrotondamento.

+0

intendevi NUMERICO (32,6)) ?? Se la somma deve essere 38 – Edmondo1984

+0

@ Edmondo1984 Si prega di leggere i collegamenti e capire cosa significano entrambi i numeri. –

+0

Si dice che moltiplicando due numeri (24,8) il server proverà a salvare 16 bit e produrrà un (32,6), come diventerà un 38,6?Grazie – Edmondo1984

0

Seguendo la logica sottolineato dalla eed3si9n e quello che hai detto nella tua domanda sembra che l'approccio migliore quando si fa la matematica operazioni è quello di estrarli in una funzione e inoltre di specificare la precisione dopo ogni operazione,

E questo caso la funzione potrebbe essere simile:

create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8)) 
returns numeric(24,8) 
as 
begin 
    declare @d as numeric(24,8) 
    set @d = @b* @c 
    return @a + @d 
end 
+0

Questo approccio potrebbe non risolvere il problema di SQL Server che taglia le parti decimali. Per salvare le parti decimali, potrebbe essere necessario eseguire il cast in @a e @b in double. –

+0

Grazie, lo terrò a mente quando lavoro su alcuni matematici di precisione in SQL, finora non ho avuto bisogno di usarlo ma è bene ora che ci possano essere alcuni problemi da considerare – kristof

Problemi correlati