Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: petrusic - Agosto 24, 2020, 05:50:42 pm

Titolo: Update DB SQLite
Inserito da: petrusic - Agosto 24, 2020, 05:50:42 pm
Putroppo non sono riuscito a trovare esempi su come utilizzare ZQuery per eseguire con certezza l'aggiornamento di record relativi.
In questa fase di studio ho provato ad eseguire sial il commit dhe il Rollback del comando di aggiornamento.
Riporto qui le istruzioni salienti:
Impostazione oggetto ZConnection.AutoCommit = False
Codice: [Seleziona]
  writeln('sqlQry= |' + sqlQry + '|');  
{                 sqlQry= |SELECT CoVocMovvgg FROM movimgg WHERE CoVocMovvgg = 101306007 AND DtCoMovgg >= 20190824 AND DtCoMovgg <= 20200824 ORDER BY DtCoMovgg, IdMovvgg|    }

  Form1.ZQuery1.SQL.Text := sqlQry;
  Form1.ZQuery1.Open;
  totRecQRY:= Form1.ZQuery1.RecordCount;           
  writeln('totRecQry= |' + IntToStr(totRecQry) + '|');     // totRecQry= |1|
  case totRecQry of
    0:                                                   
       begin
          showMessage( 'nessun record presente');
          Exit;
       end;
  end;
  Form1.ZQuery1.SQL.Clear;
  writeln('sqlUpd= |' + sqlUpd + '|');   
{    sqlUpd= |UPDATE movimgg SET CoVocMovvgg = 101306004 WHERE CoVocMovvgg = 101306007 AND DtCoMovgg >= 20190824 AND DtCoMovgg <= 20200824|     }
  Form1.ZQuery1.SQL.Text := sqlUpd;
  Form1.ZQuery1.ApplyUpdates;
  Form1.ZQuery1.Close; 
  Form1.ZConnection1.Commit;       
 

Il contenuto delle variabili sqlQry e sqlUpd è corretto, infatti le esecuzioni della SELECT e della UPDATE dentro DB Browser funzionano perfettamente.
Tutte le istruzioni riportate sopra vengono eseguite l'una dopo l'altra, senza alcun errore d'eccezione.
I parametri selettivi interni alla SELECT ed alla UPDATE sono uguali.
Titolo: Re:Update DB SQLite
Inserito da: brunello - Agosto 24, 2020, 07:08:00 pm
sicuramente ti manca  Form1.ZQuery1.ExecSql;

  Form1.ZQuery1.SQL.Text := sqlUpd;
Form1.ZQuery1.ExecSql;
  Form1.ZQuery1.ApplyUpdates;
  Form1.ZQuery1.Close; 
Titolo: Re:Update DB SQLite
Inserito da: petrusic - Agosto 24, 2020, 10:11:22 pm
sicuramente ti manca  Form1.ZQuery1.ExecSql;
:o
Ebbene, si. Ora funziona

Secondo me, l'ExecSql era implicitamente contenuto nel comando
 Form1.ZQuery1.ApplyUpdates;

Grazie brunello

Però, se l'update viene eseguito dall'istruzione
Form1.ZQuery1.ExecSql;

quale funzione svolge la  successiva
Form1.ZQuery1.ApplyUpdates;
?
Titolo: Re:Update DB SQLite
Inserito da: petrusic - Agosto 25, 2020, 01:05:29 pm
Ho continuato a carcare ed ho trovato una guida (https://wiki.freepascal.org/SqlDBHowto) che, anche se non dedicata all'uso delle librerie ZEOS, aiuta a capire i meccanismi adottati dai vari strumenti disponibili. Da essa ho tratto delle spiegazioni che ho annotato a fianco delle istruzioni di aggiornamento DB citate nel mio posto iniziale:
Citazione
Codice: [Seleziona]
sqlUpd:=('UPDATE movimgg SET CoVocMovvgg = ' + tbTrasf[1] + ' WHERE CoVocMovvgg = ' + tbTrasf[0] + ' AND                           	DtCoMovgg >= ' + dtAmgIni +  ' AND DtCoMovgg <= ' + dtAmgFin );

Form1.ZQuery1.SQL.Clear; (svuoto il contenuto della proprietà SQL dell’oggetto ZQuery)

Form1.ZQuery1.SQL.Text:= sqlUpd; (copio il contenuto della variabile sqlUpd nella proprietà  SQL.Text dell’oggetto ZQuery

Form1.ZQuery1.ExecSql; (il metodo ExecSql è quello che mi permette rendere immediatamente visibili  le modifiche nel set di dati)

Form1.ZQuery1.ApplyUpdates;(il metodo  ApplyUpdates permette di inviare tutte le modifiche dal Dataset al al database).
A questo punto però, le modifiche non sono ancora staticizzate nel DB: occorre dare conferma di quanto modificato. Tuttavia. è ancora possibile annullarle tutte in un solo colpo, ripristinando i valori precedenti alla modifica:
Codice: [Seleziona]
Form1.ZConnection1.Commit; (il metodo Commit è quello che permette di confermare e salvare definitiva le modifiche apportate al DB)

Form1.ZConnection1.Rollback; (il metodo Rollback è quello che annulla le modifiche riportando il DB coi suoi valori iniziali)
Se non ho capito, vi prego di illuminarmi.
Titolo: Re:Update DB SQLite
Inserito da: Stilgar - Agosto 25, 2020, 11:06:26 pm
Ciao.
Permesso che Zeos e la guida che hai menzionato poco si sposano tra loro.
Quello che dici è tendenzialmente giusto.
Nel senso che Zeos permette l'autocommit.
Qui si entra nel mondo delle transazioni relazionali.


Una transazione è un insieme di operazioni a database. Puoi averne bisogno o meno.
Se attivi l'auto commit non puoi eseguire il "rollback" (come un ctrl+Z sul db).


Tra i metodi che mette a disposizione Zeos puoi trovare anche "open".
Cosa usare dipende dal tipo di istruzione che metti nella stringlist che punti con la property SQL.


Nel caso "Clear", "Text := " Lanciati in sequenza sono ridondanti.
La concatenazione dell'update la esegui attraverso un'altra variabile.
Per migliorare la leggibilità dell'istruzione update ti consiglio di usare la funzione Format (https://www.freepascal.org/docs-html/rtl/sysutils/format.html). O in alternativa, visto che Zeos supporta anche quel modo, usare la "variabili" nello statement SQL. Poi tramite ZQuery imposti i vari parametri, prima dell'esecuzione.


Zeos dimostra la sua potenza, appena abbandoni i componenti visuali. Hai molto più controllo sul DB :) Fino ad incasinarti con i parametri di connessione su server configurati malino o in modo parziale.


Stilgar



Titolo: Re:Update DB SQLite
Inserito da: petrusic - Agosto 27, 2020, 11:11:48 pm
La concatenazione dell'update la esegui attraverso un'altra variabile.
Per migliorare la leggibilità dell'istruzione update ti consiglio di usare la funzione Format (https://www.freepascal.org/docs-html/rtl/sysutils/format.html). O in alternativa, visto che Zeos supporta anche quel modo, usare la "variabili" nello statement SQL. Poi tramite ZQuery imposti i vari parametri, prima dell'esecuzione.

Ho letto attentamente la funzione Format senza, però riuscire a legarne l'uso all'istruzione Update. Mi dispiace, ma non riesco a capire quanto hai cercato di indicarmi

Visto che parli di
Citazione
usare la "variabili" nello statement SQL
ti sarai accorto che io utilizzo esclusivamente statement SQL, con dentro le varibili coi parametri di trattamento record di DB.
Hom disabilitato l'Autocommit, proprio per potere decisere se e quando comandare il Commit, oppure rinunciare alle modifiche, tramite il comando Rollback.
Titolo: Re:Update DB SQLite
Inserito da: Stilgar - Agosto 29, 2020, 09:15:47 pm
parto dall'ultima asserzione.
No stai usando delle costanti.
Nel senso che l'sql che generi è una stringa. Costante nell'esecuzione dello statement.
L'uso delle variabili si basa sull'uso dei place holder.
Ne esistono di 2 tipi.
Con i componenti il formato é :nome variabile mentre a basso livello si usa '?'.
Zeos con i componenti grafici lavora ad alto livello. Per simulare il comportamento dei compinenti dataaware di delphi.

Titolo: Re:Update DB SQLite
Inserito da: petrusic - Agosto 29, 2020, 10:40:34 pm
Ho quasi risolto.
Per mia necessità, sono costretto ad usare le variabili. Oggi ho fatto un bel passo avanti, riuscendo a completare l'UPDATE di due tabelle del DB. Riporto parte del codice scritto:
Codice: [Seleziona]
Implementation
---
type
  TtbQryID = array of array[0..1] of String;
  TtbTrasf = array[0..3] of String;       
...
var
...
tbTrasf: TtbTrasf;
tbQryID: TtbQryID;
...
function DbUpdate(indCol: Integer; sql: String): Integer;    // indCol:= Indice di colonna di tbQryID, per prelevare i cod.ID dei record da aggiornare dul DB
var
  i, lun: Integer;
begin
  lun:= Length(tbQryID) - 1;
  for i:= 0 to lun do
  begin
    try
    sql:= sql + tbQryID[i, indCol];
    Form1.ZQuery1.SQL.Text:= sql;
    Form1.ZQuery1.ExecSql;
    Form1.ZQuery1.ApplyUpdates;
    except on E: exception do
      begin
        ShowMessage('ERRORE: |' + E.message + '|' );
        Application.Terminate;
      end;
    end;
  end;
  Result:= i + 1;
end;
...
procedure TForm1.BAvantiClick(Sender: TObject);
var       
numUpd1, numUpd2: Integer; 
...
begin
...
    sqlUpd:= 'UPDATE movimgg SET CoVocMovvgg = ' + tbTrasf[1] + ' WHERE IdMovvgg = ';
    numUpd1:=DbUpdate(0, sqlUpd);   // 0:= indice di col. in tbQryID per aggiornare "movimgg"
    sqlUpd:= 'UPDATE partmovv SET CoVoPartGlob = ' + tbTrasf[3] + ' WHERE IdPartGlob = ';
    numUpd2:=DbUpdate(1, sqlUpd);   // 1:= indice di col. in tbQryID per aggiornare "partmovv" o "prestmom"
    ShowMessage('*** TRASFERIMENTO terminato con SUCCESSO *** ' +
                    System.lineending + 'Reord trasferiti:  in "movimgg": n.' + IntToStr(numUpd1) + '  -  in "partmovv": n. ' + IntToStr(numUpd2));
...
end;
 
Non ho capito come utilizzare  l'intervallo try ... Except, perchè non sono sicuro di avere fatto bene o se, invece, debba scriverne uno per ciscuna riga di tipo ZQuery.
Titolo: Re:Update DB SQLite
Inserito da: Stilgar - Agosto 31, 2020, 09:21:01 am
Ciao.In caso di eccezione, capita quale eccezione viene sollevata, dovresti gestirla.
Se nell'eccezione viene riportato che la chiave è duplicata (esempio) dovresti fare in modo di non operare un insert ma un'update.
Se nell'eccezione (altro esempio) trovi che hai operato una divisione per zero, restituire (nel caso di una funzione che dovessere fare una diviso) zero o rilanciare a sua volta un'eccezione.
In altre parole, nell'except puoi fare qualche cosa, me è contestuale all'errore e a quello che stai facendo.Non esiste una regola aurea su cosa mettere dentro le except.


Stilgar