Problema con arrotondamento decimale automatico


11

La domanda è relativamente semplice. Ho bisogno di calcolare 3 colonne in cui i risultati medi sono decimali enormi, e mi imbatto in un problema all'inizio con SQL Server sostanzialmente arrotondando i decimali indipendentemente da qualsiasi cast / convertito.

Ad esempio, facciamo una divisione semplice come 1234/1233. Una calcolatrice produrrà 1.00081103000811. Ma quando lo faccio su SQL Server, otteniamo quanto segue:

-- 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

Perché si verifica questo arrotondamento automatico? E qual è il modo migliore per calcolare valori decimali follemente lunghi quando non puoi essere sicuro di quanto sarà grande un numero (la parte int o dec), poiché la tabella può contenere vari valori diversi?

Grazie!

Risposte:


17

tl; dr

Non eseguire calcoli in linguaggio SQL

Più a lungo

La scala dei risultati e la precisione sono ben definite qui su MSDN . Non è intuitivo, davvero. Tuttavia, in termini semplici, la precisione si perde quando le scale di input sono alte perché le scale dei risultati devono essere portate a 38 con un calo di precisione corrispondente.

Per confermare le cose

  • Il tuo CAST aggiuntivo nel primo esempio aggiunge semplicemente zero
  • Il troncamento avviene secondo il mio collegamento MSDN (secondo esempio)
  • Il terzo esempio con costanti ha implicato valori decimali che sono appena sufficienti (5,1) e 18,14).
    Ciò significa che la scala dei risultati e la precisione non hanno troncamento (vedi soffio)

Altre informazioni sul 1 ° e 3 ° caso.

La scala dei risultati per una divisione è max(6, s1 + p2 + 1):

  • Primo esempio, questo è 77 che è sceso a 38. La precisione è forzata allo stesso modo, con un minimo di 6 (vedi questo )
  • Terzo esempio, questo è 24 quindi la precisione non ha bisogno di essere regolata

Hai alcune opzioni

  • calcolare nel codice client, ad es. .net
  • utilizzare le funzioni CLR per eseguire calcoli .net
  • vivere con la perdita di precisione
  • usa float e vivi con 15 figure significative come meglio

Infine, vedi questo su /programming/423925/t-sql-decimal-division-accuracy/424052#424052


1

Non sono sicuro se questo aiuta, ma per me la mia colonna della tabella temporanea era impostata su decimale, stavo passando convert (decimale (15,2), 0,65) dall'inserto in temp_table. Questo è stato l'arrotondamento automatico, ho cambiato il tipo di colonna in decimale (16,2) per adattarlo a ciò che veniva passato. La tabella ora sta memorizzando 0,65.


1

Ho dovuto lavorare intorno. Ecco cosa ho fatto:

-----------------------------------
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

risultati:

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

Spero che questo ti aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.