none
Strano troncamento alla sesta cifra decimale RRS feed

  • Domanda

  • Ciao a tutti,
    non riesco a capire come mai SQL Server mi tronchi dei dati numerici alla sesta cifra decimale, quando invece i decimali dovrebbero essere ben di più.
    Ecco l'esempio.
    Ho queste 3 tabelle con dei dati di prova:

    create table Consumi1 (Combustibile varchar(10), Valore decimal(30,19))
    go
    create table Consumi2 (Combustibile varchar(10), Valore decimal(30,19))
    go
    create table Consumi3 (Combustibile varchar(10), Valore decimal(30,19))
    go
    insert Consumi1 values ('Carbone', 123.4567898765434), ('OCD',456.574747473737), ('Gasolio',9987.8473736666)
    insert Consumi1 values ('Carbone', 523.5499292929292), ('OCD',868.183837474744), ('Gasolio',45.57575757388)
    go
    insert Consumi2 values ('Carbone', 123.4567898765434), ('OCD',456.574747473737), ('Gasolio',9987.8473736666)
    insert Consumi2 values ('Carbone', 123.3434343434343), ('OCD',436.443243434343), ('Gasolio',97.12121212121)
    go
    insert Consumi3 values ('Carbone', 123.4567898765434), ('OCD',456.574747473737), ('Gasolio',9987.8473736666)
    insert Consumi3 values ('Carbone', 56.5638383838383), ('OCD',45.583838383827), ('Gasolio',995.438280282828)

    I dati numerici sono assolutamente casuali, ma servono solo per mettere un abbondante numero di cifre decimali.

    Se faccio la seguente query di aggregazione:

    select a.combustibile, SUM(a.valore)
    from
    (
    select Combustibile, SUM(valore) valore
    from consumi1
    group by combustibile) a
    inner join (
    select Combustibile, SUM(valore) valore
    from consumi2
    group by combustibile ) b
    on a.combustibile = b.Combustibile
    group by a.Combustibile

    ottengo i valori:

    combustibile (No column name)
    Carbone 647.0067191694726000000
    Gasolio 10033.4231312404800000000
    OCD 1324.7585849484810000000


    che, come si vede, hanno ben più di 6 decimali (e così mi va bene), mentre se invece faccio delle operazioni di moltiplicazione e divisione, come nella seguente query:


    select a.combustibile,
    (SUM(a.valore)*SUM(b.valore))/SUM(b.valore)
    from
    (
    select Combustibile, SUM(valore) valore
    from consumi1
    group by combustibile) a
    inner join (
    select Combustibile, SUM(valore) valore
    from consumi2
    group by combustibile ) b
    on a.combustibile = b.Combustibile
    group by a.Combustibile


    ottengo dei valori "troncati" alla sesta cifra decimale:

    combustibile (No column name)
    Carbone 647.006719
    Gasolio 10033.423131
    OCD 1324.758584

    Come mai questo strano comportamento?

    Grazie

    Luigi

    mercoledì 21 aprile 2010 18:29

Risposte

  • Ciao Luigi,

    il comportamento è documentato qui
    ----
    Precisione, scala e lunghezza
    http://msdn.microsoft.com/it-it/library/ms190476.aspx
    ----

    guarda come avviene l'assegnazione della precisione e della scala in caso di moltiplicazione e anche dove dice:
    ----
    * La precisione e la scala del risultato hanno un valore massimo assoluto pari a 38. * Quando la precisione del risultato è superiore a 38, la scala corrispondente viene ridotta per evitare il troncamento della parte intera del risultato.
    ----

    Per risolvere puoi fare così:
    ----
    select a.combustibile,
    SUM(a.valore)*SUM(b.valore)/SUM(b.valore) TotValore
    from
    (
       select Combustibile, Convert(Float,SUM(valore)) valore
       from consumi1
       group by combustibile) a
       inner join
       (select Combustibile, Convert(Float,SUM(valore)) valore
        from consumi2
        group by combustibile
       ) b on a.combustibile = b.Combustibile
    group by a.Combustibile
    ----

    a mio parere è meglio se definisci Float i campi Valore delle tabelle, mi sembra il tipo di dato più appropriato per il tuo caso.

    Ciao
    Giorgio Rancati

    • Contrassegnato come risposta Ciupaz giovedì 22 aprile 2010 08:23
    mercoledì 21 aprile 2010 19:13
    Moderatore

Tutte le risposte

  • Ciao Luigi,

    il comportamento è documentato qui
    ----
    Precisione, scala e lunghezza
    http://msdn.microsoft.com/it-it/library/ms190476.aspx
    ----

    guarda come avviene l'assegnazione della precisione e della scala in caso di moltiplicazione e anche dove dice:
    ----
    * La precisione e la scala del risultato hanno un valore massimo assoluto pari a 38. * Quando la precisione del risultato è superiore a 38, la scala corrispondente viene ridotta per evitare il troncamento della parte intera del risultato.
    ----

    Per risolvere puoi fare così:
    ----
    select a.combustibile,
    SUM(a.valore)*SUM(b.valore)/SUM(b.valore) TotValore
    from
    (
       select Combustibile, Convert(Float,SUM(valore)) valore
       from consumi1
       group by combustibile) a
       inner join
       (select Combustibile, Convert(Float,SUM(valore)) valore
        from consumi2
        group by combustibile
       ) b on a.combustibile = b.Combustibile
    group by a.Combustibile
    ----

    a mio parere è meglio se definisci Float i campi Valore delle tabelle, mi sembra il tipo di dato più appropriato per il tuo caso.

    Ciao
    Giorgio Rancati

    • Contrassegnato come risposta Ciupaz giovedì 22 aprile 2010 08:23
    mercoledì 21 aprile 2010 19:13
    Moderatore
  • Ciao Giorgio,
    e io che pensavo che il decimal fosse il tipo di dato più corretto ed indicato in questa situazione. Non ci avevo pensato proprio a provare a cambiarlo.
    Ora faccio un po' di test con la tua soluzione.
    Ti ringrazio moltissimo, sei stato più che utile.

    Luigi

    giovedì 22 aprile 2010 08:23