Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14
  1. #1
    Utente di HTML.it
    Registrato dal
    Dec 2002
    Messaggi
    1,315

    [delphi] round in stored procedure

    Salve a tutti, ciao Alka,

    dovrei effettuare dei calcoli in una stored procedure,..ed avrei bisogno di arrotondare a 3 cifre decimali dei valori numerici nella stored procedure.

    credo di aver bisogno di una funzione UDF che effettua il ROUND.

    mi sapete indicare quale libreria posso utilizzare e da dove la posso scaricare, o e meglio che me la costruisca io?

    grazie

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Non arrotondare all'interno della stored procedure con il rischio di perdere precisione, bensì usa l'arrotondamento all'interno di Delphi come semplice rappresentazione del valore.

    Inoltre, mi sono dimenticato di farti un appunto riguardo ad un altra discussione in cui hai postato parte del codice della stored procedure: evita l'uso del tipo double precision quando lavori con degli importi, poichè si tratta di un valore a virgola mobile che ha difetti di precisione e può portarti a risultati errati nell'esecuzione di calcoli fiscali. Al suo posto, usa il tipo numeric, il quale invece memorizza il tuo valore, pur essendo decimale, usando registri interi e quindi non influenzati da alcuna perdita di precisione.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    Utente di HTML.it
    Registrato dal
    Dec 2002
    Messaggi
    1,315
    il problema e' proprio questo...la perdita di precisione.

    io devo calcolare il totale di valori quali imponibile e imposta.

    nel programma in delphi questi 2 fields sono fields calcolati, ed io per ogni record eseguo il calcolo:
    codice:
    procedure TFrmMovimenti.IBDataSet1CalcFields(DataSet: TDataSet);
    begin
     with IBDataSet1 do
      begin
      FieldByName('IMPONIBILE').AsFloat := (FieldByName('QUANTITA').AsFloat * FieldByName('PREZZO').AsFloat) - ((FieldByName('QUANTITA').AsFloat * FieldByName('PREZZO').AsFloat) * FieldByName('SCONTO').AsFloat /100);
      FieldByName('IMPOSTA').AsFloat := FieldByName('IMPONIBILE').AsFloat * FieldByName('IVA').AsFloat /100 ;
      FieldByName('TOTALE').AsFloat := FieldByName('IMPONIBILE').AsFloat + FieldByName('IMPOSTA').AsFloat;
      end;
    end;
    ad esempio, il fields imposta e' definito numeric 9,3 e quindi viene automaticamente arrotondato alla terza cifra decimale, e questo arrotondamento avviene singolarmente per ogni record di dettaglio_movimento.

    nella stored procedure calcolo i totali in questo modo:
    codice:
    CREATE PROCEDURE TOTALI_DET (
        IDMOVIMENTI INTEGER)
    RETURNS (
        IMPONIBILE NUMERIC(15,3),
        IMPOSTA NUMERIC(15,3),
        TOTALE NUMERIC(15,3))
    AS
    begin
      /* Procedure Text */
    SELECT 
    SUM((quantita*prezzo)-(quantita*prezzo*sconto/100)),
    SUM((quantita*prezzo)-(quantita*prezzo*sconto/100)*iva/100),
    SUM(((quantita*prezzo)-(quantita*prezzo*sconto/100))+((quantita*prezzo)-(quantita*prezzo*sconto/100))*iva/100)
    FROM movimenti_dettaglio
    where id_movimenti = :idmovimenti
    INTO :imponibile, :imposta, :totale;
    suspend;
    end
    questo fa si, che l'arrotondamento non avviene singolarmente per ogni record, bensi solo alla fine della SUM, e quindi ottengo dei totali che possono essere diversi dalla somma delle cifre che effettivamente visualizzo.

    cosa mi consigli di fare?

    ps.: quando mi hai detto di utilizzare fields numeric invece di double intendevi come dovevo dichiarare le variabili di RETURNS della stored NUMERIC?

    grazie

  4. #4
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Quando ti dicevo di sostituire NUMERIC a DOUBLE PRECISION, mi riferivo a tutti gli ambiti in cui devi memorizzare o eseguire calcoli con valute, quindi campi del database, variabili nelle stored procedure e così via.

    Comunque, non comprendo bene come hai organizzato il lavoro: il totale lo calcoli in Delphi o nella stored procedure?

    Inoltre, il listato della stored procedure mi sembra molto contorto: tutto viene eseguito con una istruzione SELECT; ricorda che è possibile utilizzare l'istruzione FOR SELECT per poter eseguire un blocco di istruzioni tante volte quanti sono i record restituiti dalla SELECT stessa: questo è utile per calcolare totali scandendo ogni record, eseguendo il calcolo per il singolo record e aggiungendo il valore ottenuto al totale sommario.

    Il valore da visualizzare in Delphi deve poi essere formattato alle cifre decimali desiderate usando la proprietà DisplayFormat, se queste cifre sono diverse da quelle utilizzate nel campo stesso del database.

    Non userei la proprietà AsFloat, bensì la proprietà AsCurrency (se possibile), visto che il tipo Double di Delphi ha lo stesso problema del tipo DOUBLE PRECISION di InterBase: sono valori a virgola mobile con perdita di precisione.

    Se la proprietà AsFloat viene usata per ottenere il valore di un campo valuta da arrotondare e visualizzare, grossi problemi non sussistono comunque, ma se inizi a sommarli tra loro per fare calcoli, allora alla fine è facile che tu ottenga un risultato diverso da quello corretto per via della perdita di precisione che si propaga ad ogni operazione di somma ripetuta.

    Spero di averti dato sufficienti indicazioni.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  5. #5
    Utente di HTML.it
    Registrato dal
    Dec 2002
    Messaggi
    1,315
    scusa per favore, stavo scrivendo una stored con cui vorrei far calcolare il totale dell'imponibile scandendo ogni singolo record...

    quindi, io seleziono tutti i record di dettaglio e per oguno di essi sommerei l'imponibile.
    dapprima ho impostato IMPONIBILE=0, poi eseguo la SELECT...poi si ferma sull'istruzione DO con questo messagio:
    codice:
    ================================================================================
    ********* Statement:
    REATE PROCEDURE TOTALI_DETDO (
        IDMOVIMENTI INTEGER)
    RETURNS (
        IMPONIBILE NUMERIC(15,3))
    AS
    begin
      /* Procedure Text */
    IMPONIBILE=0;
    FOR SELECT * FROM movimenti_dettaglio where id_movimenti LIKE :idmovimenti
    DO
      BEGIN
       IMPONIBILE = IMPONIBILE + ((quantita*prezzo)-(quantita*prezzo*sconto/100))
       suspend;
      END
    end
    
    ********* Error:
    Invalid token.
    Dynamic SQL Error.
    SQL error code = -104.
    Token unknown - line 10, char -1.
    DO.
    da un esempio che ho trovato sul manuale di interbase/firebird la mia stored differisce solo x la clausa INTO a seguito della select.

    ma la mia select non mi restituisce un parametro da inserire in RETURNS....

    dove sbaglio?

  6. #6
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    La clausola INTO è obbligatoria nell'istruzione FOR SELECT, poichè i valori dei campi devono essere memorizzati all'interno di variabili locali che verranno poi usate per eseguire i calcoli dovuti: il codice compreso tra DO BEGIN...END non può accedere ai campi usando i nomi corrispondenti.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  7. #7
    Utente di HTML.it
    Registrato dal
    Dec 2002
    Messaggi
    1,315
    ecco fatto:
    codice:
    CREATE PROCEDURE TOTALI_DETDO (
        IDMOVIMENTI INTEGER)
    RETURNS (
        IMPONIBILE NUMERIC(15,3),
        IMPOSTA    NUMERIC(15,3),
        TOTALE     NUMERIC(15,3)
        )
    AS
    DECLARE VARIABLE QUANTITA_ NUMERIC(15,3);
    DECLARE VARIABLE PREZZO_   NUMERIC(15,3);
    DECLARE VARIABLE SCONTO_   NUMERIC(15,3);
    DECLARE VARIABLE IVA_      NUMERIC(15,3);
    DECLARE VARIABLE IMPON_    NUMERIC(15,3);
    DECLARE VARIABLE IMPOS_    NUMERIC(15,3);
    begin
      /* Procedure Text */
    IMPONIBILE=0;
    IMPOSTA=0;
    TOTALE=0;
    FOR SELECT quantita,prezzo,sconto, iva  FROM movimenti_dettaglio
    where id_movimenti LIKE :idmovimenti
    into :quantita_, :prezzo_, :sconto_, :iva_
    DO
      BEGIN
       IMPON_     = ((:quantita_* :prezzo_)-(:quantita_ * :prezzo_ *:sconto_ /100));
       IMPONIBILE = IMPONIBILE + IMPON_;
       IMPOS_     = IMPON_ * :IVA_ /100;
       IMPOSTA    = IMPOSTA + IMPOS_;
      END
       TOTALE     = IMPONIBILE +IMPOSTA;
      suspend;
    end
    in questa maniera ottengo i risultati giusti....

    resta una cosa da fare, e cioe controllare se i valori :quantita_ rezzo_ :sconto_ :iva_ sono null.

    come mi consigli di fare? controllare nella stored o direttamente inserire l'opzione NOT NULL nelle proprieta del field della tabella del database?

    grazie

    ps....scusami ma nn so xke sono uscite tutti queste faccine che ridono... forse per una semplice consecutivita di caratteri.

  8. #8
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296
    Se si tratta di dati che devono essere obbligatoriamente inseriti, la clausola NOT NULL va inserita nel campo, all'interno della struttura della tabella.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  9. #9
    Utente di HTML.it
    Registrato dal
    Dec 2002
    Messaggi
    1,315
    io l'ho definito cosi....

    QUANTITA NUMERIC(9,3) DEFAULT '0' NOT NULL,

    succede che se inserisco tramite IBExpert un record, nel momento che eseguo il Post se il valore della quantita e' null viene automaticamente settato a 0., invece in delphi mi viene sollevata un'eccezzione che indica che il field quantita non puo' essere Null costringendomi a dover scrivere un valore.

    non si puo avere l'assegnazione automatica x default?

  10. #10
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,296

    Required

    Originariamente inviato da 123delphi321
    non si puo avere l'assegnazione automatica x default?
    Il valore di default viene attribuito da InterBase quando, per un determinato campo, si tenta di impostare un valore nullo.

    Questo avviene anche in Delphi, ma siccome la struttura interna (oggetti TFields) della tabella prevede il valore True per la proprietà Required del campo, Delphi pretende di ottenere un valore da inviare per quel campo prima di eseguire la Post.

    La soluzione è semplice: intercetta l'evento OnNewRecord sul DataSet e, in tale evento, attribuisci valori iniziali ai campi.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.