Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: petrusic - Aprile 16, 2020, 07:34:30 pm

Titolo: [Risolto] accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 16, 2020, 07:34:30 pm
Procedendo nel mio cammino, ho dato inizio alla lettura di una tabella di DB, sfruttando quanto già appreso durante e dopo l'installazione di ZEOS.
Premetto che,  ho creato e configurato :
Citazione
ZConnection1: TzConnection coi seguenti componenti
- Database= /media/dirdati/dativari/contabfam/ContabFamdb_prove
- HostName= petrus-pc
- Protocol= sqlite-3
- Connected= True

ZQuery1:TZQuery  soltanto con
- Connection= ZConnection1

contabFamDB: TDataSource con
- DataSet= ZQuery1

A questo punto, seguendo quanto riportato qui (http://www.lazaruspascal.it/index.php?topic=2283.msg14182#msg14182), ho scritto
Codice: [Seleziona]
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, db, Forms, Controls, Graphics, Dialogs, StdCtrls, EditBtn,
  ExtCtrls, DBGrids, DBCtrls, ZConnection, ZDataset;
type
  { TForm1 }

  TForm1 = class(TForm)
    VoMasArri: TComboBox;
    VoMasPart: TComboBox;
    contabfamDB: TDataSource;
    DBSotCtoArri: TDBComboBox;
    DBVoSecArri: TDBComboBox;
    DbVoSecPart: TDBComboBox;
    DBSotCtoPart: TDBComboBox;
    pExit: TButton;
    PNoVis: TButton;
    DtFin: TDateEdit;
    DtIni: TDateEdit;
    Label5: TLabel;
    Label6: TLabel;
    pVia: TButton;
    CoVoPart: TEdit;
    CoVoArri: TEdit;
    Label3: TLabel;
    Label4: TLabel;
    MovDest: TGroupBox;
    SotCtoPart: TComboBox;
    Label2: TLabel;
    SotCtoArri: TComboBox;
    VoSecPart: TComboBox;
    Label1: TLabel;
    MovTrasf: TGroupBox;
    VoSecArri: TComboBox;
    ZConnection1: TZConnection;
    ZQuery1: TZQuery;
    procedure FormActivate(Sender: TObject);
    procedure pExitClick(Sender: TObject);
    procedure pExitEnter(Sender: TObject);
    procedure pExitExit(Sender: TObject);
    procedure PNoVisEnter(Sender: TObject);
    procedure VoMasPartChange(Sender: TObject);   
procedure carCombo(Fmastro: String); 
var
  rs: TZQuery;
--- bla --- bla ---

begin                 
--- bla --- bla ---
 sql:= sql1 + sql2 + ' order by NumVoce';

  ZQuery1.SQL.Text := sql;
  ZQuery1.Open;
  FtotRecquery:= rs.RecordCount;             
  SetLength(tbDBpiancont, FtotRecquery,5);
  n := 0;
  while rs.next do
  begin
    tbDBpiancont[i,0]:= rs.GetFieldData(NumVoce);
    tbDBpiancont[i,1]:= rs.GetFieldData(NomeVoce);
    tbDBpiancont[i,2]:= rs.GetFieldData(ContrPartSiNo);
    tbDBpiancont[i,3]:= rs.GetFieldData(DtPrimoUso);
    tbDBpiancont[i,4]:= rs.GetFieldData(DtUltimUso);
    n:= +1;
  end;

Risultato : segnalati errori per non aver trovato:
ZQuery1 e tutti i campi delle tabella che volevo acquisire con  rs.GetFieldData

Non capisco perhè non viene riconosciuto ZQuery1, se è riportato, senza segnalazione di errore, fra i type dopo gli uses della unit.

Non ho capito poi come identificare, per nome campo, le celle di ciascuna colonna della tabella; così come ho fatto è sicuramente sbagliato, ma la guida (http://www.lazaruspascal.it/index.php?page=111) richiama metodi che non sono riuscito a caire come mettere in pratica  (come cursor.get[xxxxx] ByName(nome della colonna).

Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: xinyiman - Aprile 17, 2020, 08:09:27 am
Deduco da quello che scrivi che i componenti non li hai trascinati sulla form con il drag and drop, quindi devi crearli tu a mano.
Lo TZQuery è una classe e come tale va creata quindi devi scrivere qualcosa del genere

  ZQuery1 := TZQuery.Create(nil);
  ZQuery1.SQL.Text := sql;

  ZQuery1.Close;
  ZQuery1.Free;
  ZQuery1 := nil;
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 17, 2020, 10:04:06 am
Deduco da quello che scrivi che i componenti non li hai trascinati sulla form con il drag and drop, quindi devi crearli tu a mano.
Questo non è vero, perchè ci sono tutti e ben visibili, come puoi constatare dall'immagine allegata. Se poi ciò non basta e bisogna comandare il create, per me è una novità, perchè in un precedente esercizio di prova, in cui però ho aggiunto una DBGrid, la query è stata eseguita ed il risultato è stato reso visibile dentro la DBGrid, senza scrivere nemmeno una riga di codice.

Tornando al programma che sto provando ora, oggi ho tentato anche ad impostare la proprieta ZQuery1.Active= TRUE, ma non è cambiato niente, l'errore si ripresenta implacabile.
Scusami se insisto, ma vorrei capire e ancora non ho capito.

Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: xinyiman - Aprile 17, 2020, 01:30:58 pm
Io di solito faccio come segue

Disegno il componente TZQuery (ovviamente collegato al TZConnector) poi nella procedura scrivo qualcosa tipo:

Codice: [Seleziona]
var
ZQuery1 : TZQuery;
...

procedure TForm1.ScorriDati();
var
    a : string;
    b : integer;
    n : integer; //numero di record
begin
         ZQuery1.SQL.text := 'select campo1, campo2 from mia_tabella';
         ZQuery1.Open;
         if not ZQuery1.EOF then
         begin
               n:=ZQuery1.RecordCount();
               ZQuery1.First;
               while not ZQuery1.EOF do
               begin
                       a := ZQuery1.FieldByName('campo1').AsString;
                       b := ZQuery1.FieldByName('campo2').AsInteger;
                       ZQuery1.Next;
               end;
         end;
         ZQuery1.Close;
end;

Poi fai quello che vuoi con i dati. Con la sintassi sono andato a memoria potrei aver sbagliato qualcosa.
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: Stilgar - Aprile 17, 2020, 03:57:16 pm
Ciao petruscic.
Da quel poco che leggo del codice, definisci un componente Query e poi ne disegni un altro.
Premesso che quel rs.next potrebbe aver problemi a runtime (non ho letto dove lo crei, quindi ho il dubbio).
Se non vede Query1, potrebbe essere che stai facendo "confusione" con le variabili? Nel senso che in quel metodo, per qualche motivo, query1 è un'altra cosa? Se fosse possibile leggere tutto il codice della classe, magari potremmo capire meglio cosa succede :)

Stilgar
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 17, 2020, 05:45:47 pm
Ho capito. La

 var
   ZQuery1: TZQuery;

mancava e  l'ho aggiunta. Poi però ho adeguato il mio codice al tuo esempio. Così facendo, la compilazione si è conclusa senza errori.

Tuttavia l'esecuzione dà il seguente errore:
Citazione
Il progetto cofamtrasflpi ha sollevato una eccezione di classe 'External: SIGSEGV'.

 Nel file '../../src/component/ZAbstractRODataset.pas' alla riga 2234:
Result := FSQL;
L'errore si manifesta nell'esecuzione dell'istruzione
Codice: [Seleziona]
 ZQuery1.SQL.Text := sql; 
In quel momento la variabile sql contiene:
Citazione
sql= SELECT * FROM piancont WHERE (NumVoce >= 101000000 AND NumVoce <= 101001799) OR (NumVoce >= 101001990 AND NumVoce <= 101001999) ORDER BY NumVoce

// valore rilevato tramite writeLn subito prima della "ZQuery1.SQL.Text := sql"


Allo stesso momento, guardando invece nella finestra di debug.Local Variables,trovo invece il seguente contenuto:
Citazione
SQL   'SELECT * FROM piancont WH###(gdb unparsed remainder....)###'

Che significa?
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 17, 2020, 06:04:35 pm
Ciao petruscic.
Da quel poco che leggo del codice, definisci un componente Query e poi ne disegni un altro.
Premesso che quel rs.next potrebbe aver problemi a runtime (non ho letto dove lo crei, quindi ho il dubbio).
Se non vede Query1, potrebbe essere che stai facendo "confusione" con le variabili? Nel senso che in quel metodo, per qualche motivo, query1 è un'altra cosa? Se fosse possibile leggere tutto il codice della classe, magari potremmo capire meglio cosa succede :)

Stilgar
Si hai ragione, infatti stamani sono entrato un pò nel pallone, ma poi, rileggendo il codice e riflettendo sulle istruzioni d'esempio che mi ha gentilmente passato xinyiman, ho ricostruito l'impostazione del ResultSet e mi sono accorto così che mancava solamente la var relativa a ZQuery1, anche perchè secondo me, avrebbe dovuto essere già presente in automatico, invece in automatico viene formata solo la type Zquery1: TZQuery.

Purtroppo ora il programma si interrompe durante l'esecuzione.
Comunque allego tutto il file .pas
Spero che la vostra esperienza mi possa accendere un'altra lampadina.
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: Stilgar - Aprile 18, 2020, 01:43:40 am
Codice: [Seleziona]


unit cofamtrasf;   {Classe: tipo Form_Main}

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, db, Forms, Controls, Graphics, Dialogs, StdCtrls, EditBtn,
  ExtCtrls, DBGrids, DBCtrls, ZConnection, ZDataset;

type
  { TForm1 }

  TForm1 = class(TForm)
    VoMasArri: TComboBox;
    VoMasPart: TComboBox;
    contabfamDB: TDataSource;
    DBSotCtoArri: TDBComboBox;
    DBVoSecArri: TDBComboBox;
    DbVoSecPart: TDBComboBox;
    DBSotCtoPart: TDBComboBox;
    pExit: TButton;
    PNoVis: TButton;
    DtFin: TDateEdit;
    DtIni: TDateEdit;
    Label5: TLabel;
    Label6: TLabel;
    pVia: TButton;
    CoVoPart: TEdit;
    CoVoArri: TEdit;
    Label3: TLabel;
    Label4: TLabel;
    MovDest: TGroupBox;
    SotCtoPart: TComboBox;
    Label2: TLabel;
    SotCtoArri: TComboBox;
    VoSecPart: TComboBox;
    Label1: TLabel;
    MovTrasf: TGroupBox;
    VoSecArri: TComboBox;
    ZConnection1: TZConnection;
    ZQuery1: TZQuery;
    procedure FormActivate(Sender: TObject);
    procedure pExitClick(Sender: TObject);
    procedure pExitEnter(Sender: TObject);
    procedure pExitExit(Sender: TObject);
    procedure PNoVisEnter(Sender: TObject);
    procedure VoMasPartChange(Sender: TObject);
  private
    procedure carCombo(Fmastro: String);
  public
  end;

 

implementation

{$R *.lfm}

{ TForm1 }

type
  Ttbpiacon = array of array of string;

const
    ctiCassa: array[0..1, 0..1] of string = (
      ('101000000', '101001799'),     // 1° range conti di Cassa (tabella piancont)
      ('101001990', '101001999')
    );       // ultimo range conti di Cassa (tabella piancont)


    ctiPart: array[0..2, 0..1] of string = (
      ('102000000', '103999999'),  // 1° range conti di contropartita pertinenti a "partmovv" (tabella piancont)
      ('105000000', '203999999'),   // 2° range conti di contropartita pertinenti a "partmovv" (tabella piancont)
      ('205000000', '999999999'))
    ; // ultimo range conti di contropartita pertinenti a "partmovv" (tabella piancont)

    ctiPrest: array[0..1, 0..1] of string = (
      ('104000000', '104999999'),     // 1° range conti di contropartita pertinenti a "prestmom" (tabella piancont)
      ('204000000', '204999999')
    );    // ultimo range conti di contropartita pertinenti a "prestmom" (tabella piancont)


procedure TForm1.FormActivate(Sender: TObject);
begin
{   
  MovTrasf.Visible:= True;
  MovDest.Visible:= True;
  pVia.Visible:= True;
  Label5.Visible:= True;
  Label6.Visible:= True;
  DtIni.Visible:= True;
  DtFin.Visible:= True;
  rispo:= MessageDlg ('Sei scuro di volere trasferire movimenti da un conto ad un altro?',  mtConfirmation, [mbYes, mbClose], 0);
  if (rispo=mrClose) then
       Application.Terminate;
}
end;

procedure TForm1.carCombo(Fmastro: String);
var
  tbDBpiancont: Ttbpiacon;   {  tabella dimemoria coi dati letti dalla tabella DB.piancont le colonne sono: |- NumVoce, NomeVoce, ContrPartSiNo, DtPrimoUso, DtUltimUso -|}
  //stmt: IZStatement
  //rs: TZQuery;
  sql, sql2: String;
  sql1: String= 'SELECT * FROM piancont WHERE ';
  {sql1: String= 'select NumVoce, NomeVoce, ContrPartSiNo, DtPrimoUso, DtUltimUso ' + ' from piancont where ';}
  FtoRecQ: integer;
  i, ii, n: integer;
begin
  case Fmastro of
    'Cas':
      sql2:= ('(NumVoce >= ' +  ctiCassa[0,0] + ' AND NumVoce <= ' + ctiCassa[0, 1] + ') OR (NumVoce >= ' + ctiCassa[1, 0] + ' AND NumVoce <= ' + ctiCassa[1, 1] + ')');
    'Part':
      sql2:= '(NumVoce >= ' +  ctiPart[0,0] + ' AND NumVoce <= ' + ctiPart[0, 1] +
             ') OR (NumVoce >= ' + ctiPart[1, 0] + ' AND NumVoce <= ' + ctiPart[1, 1] +
             ') OR (NumVoce >= ' + ctiPart[2, 0] + ' AND NumVoce <= ' + ctiPart[2, 1] + ')';
    else  // 'Prest':
      sql2:= '(NumVoce >= ' +  ctiPrest[0,0] + ' AND NumVoce <= ' + ctiPrest[0, 1] + ') OR (NumVoce >= ' + ctiPrest[1, 0] + ' AND NumVoce <= ' + ctiPrest[1, 1] + ')';
  end;
  sql:= sql1 + sql2 + ' ORDER BY NumVoce';
  WriteLn();
  WriteLn('sql= ', sql);
  ZQuery1.SQL.Text := sql;
  ZQuery1.Open;
  ZQuery1.Last;
  FtoRecQ:= ZQuery1.RecordCount;
  SetLength(tbDBpiancont, FtoRecQ,5);
  n := 0;
  ZQuery1.First;

  while not ZQuery1.EOF do
  begin
    tbDBpiancont[i,0]:= ZQuery1.FieldByName('NumVoce').AsString;
    tbDBpiancont[i,1]:= ZQuery1.FieldByName('NomeVoce').AsString;
    tbDBpiancont[i,2]:= ZQuery1.FieldByName('ContrPartSiNo').AsString;
    tbDBpiancont[i,3]:= ZQuery1.FieldByName('DtPrimoUso').AsString;
    tbDBpiancont[i,4]:= ZQuery1.FieldByName('DtUltimUso').AsString;
    ZQuery1.Next;
    n:= +1;
  end;
  ZQuery1.Close;

  for i:= 0 to n do
  begin
    WriteLn();
    for ii:= 0 to 4 do
    begin
      writeln('tbDBpiancont[', i, ' , ', ii, ']= ' + tbDBpiancont[i,ii]);
    end;
  end;
end;

procedure TForm1.pExitClick(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TForm1.pExitEnter(Sender: TObject);
begin

end;

procedure TForm1.pExitExit(Sender: TObject);
begin

end;

procedure TForm1.PNoVisEnter(Sender: TObject);
begin
{  Sleep(5000);
  pExit.SetFocus;}
end;

procedure TForm1.VoMasPartChange(Sender: TObject);

begin
     case VoMasPart.Text of
          'CASSA':
            carCombo('Cas');
          'PARTMOVV':
            carCombo('Part');
          'PRESTMOM':
            carCombo('Prest');
      end;
end;


end.

Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: Stilgar - Aprile 18, 2020, 01:43:59 am
Prova questa versione :)
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 18, 2020, 04:39:26 pm
Prova questa versione :)
Ho provato la versione modificata, anche se non mi sono soffermato sulle modifiche, perchè volevo tornarci sopra, dopo l'esecuzione.
Devo soltanto dirti che ho dovuto rimettere al suo posto
Codice: [Seleziona]
  public

    end;

  var
  Form1: TForm1;
//  ZQuery1: TZQuery;   // suggerita dal Forum


implementation
perchè, senza la dichiarazione della Form1, la compilazione mi ha dato errore.

Questa volta l'esecuzione è andata un pò più avanti, ed esattamente, ha completato le seguenti istruzioni:
Codice: [Seleziona]
procedure TForm1.carCombo(Fmastro: String);
var
  tbDBpiancont: Ttbpiacon;   {  tabella dimemoria coi dati letti dalla tabella DB.piancont
                                le colonne sono: |- NumVoce, NomeVoce, ContrPartSiNo, DtPrimoUso, DtUltimUso -|}

sql, sql2: String;
sql1: String= 'SELECT * FROM piancont WHERE ';
{sql1: String= 'select NumVoce, NomeVoce, ContrPartSiNo, DtPrimoUso, DtUltimUso ' +
              'from piancont where ';}
FtoRecQ: integer;
i, ii, n: integer;
begin
  case Fmastro of
    'Cas':
      sql2:= ('(NumVoce >= ' +  ctiCassa[0,0] + ' AND NumVoce <= ' + ctiCassa[0, 1] +
             ') OR (NumVoce >= ' + ctiCassa[1, 0] + ' AND NumVoce <= ' + ctiCassa[1, 1] + ')');
    'Part':
      sql2:= '(NumVoce >= ' +  ctiPart[0,0] + ' AND NumVoce <= ' + ctiPart[0, 1] +
             ') OR (NumVoce >= ' + ctiPart[1, 0] + ' AND NumVoce <= ' + ctiPart[1, 1] +
             ') OR (NumVoce >= ' + ctiPart[2, 0] + ' AND NumVoce <= ' + ctiPart[2, 1] + ')';
    else  // 'Prest':
      sql2:= '(NumVoce >= ' +  ctiPrest[0,0] + ' AND NumVoce <= ' + ctiPrest[0, 1] +
             ') OR (NumVoce >= ' + ctiPrest[1, 0] + ' AND NumVoce <= ' + ctiPrest[1, 1] + ')';
  end;
  sql:= sql1 + sql2 + ' ORDER BY NumVoce';
  WriteLn();
  WriteLn('sql= ', sql);
  ZQuery1.SQL.Text := sql;                   
poi si è inceppata sulla successiva
Codice: [Seleziona]
  ZQuery1.Open;
(come se fosse andata in loop) per un bel pò e, finalmente, ha prodotto una finestra col seguente messaggio d'errore
Citazione
il progetto cofamtrasflpi ha sollevato una eccezione di classe 'external: SISEGV'

all'indirizzo 434661

Mi pare che prima delle mie domande di chiarimento sia opportuno superare il nuovo ostacolo, quindi riallego il file .pas, modificato per la suddetta prova
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 19, 2020, 12:55:55 pm
Penso di avere trovato la causa del problema:
Rivedendo le impostazioni a livello di TDataSource, TZConnection e TZQuery(ZQuery1), confrontandolo con quanto riportato qui (http://www.lazaruspascal.it/index.php?page=141), ho trovato che nella guida non era valorizzato il parametro ZQuery1.DataSource.
Ho quindi ripulito l'impostazione ed ho riprovato l'esecuzione.
Ebbene, questa volta il programma non si è bloccato e non ha dato errori.
Quindi, grazie per avermi costretto a ripercorrere il mio modestissimo lavoro.
 :D
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: petrusic - Aprile 19, 2020, 04:13:44 pm
Ora che ho riprovato il programma ed accertato che sono stati letti tutti i record oggetto della query, avrei bisogno di capire alcuni aspetti delle modifiche suggerite.

Perchè è stato necessario aggiungere la riga di codice seguente:
Codice: [Seleziona]
private
    procedure carCombo(Fmastro: String);    // riga aggiunta da sugerimento del Forum
  public         
 
  end;

Perchè non è necessaria la riga seguente, commentata:
Codice: [Seleziona]
 var
  Form1: TForm1;
//  ZQuery1: TZQuery;   // commentata per suggerimento dal Forum


implementation                                                       


Perchè è stato necessario spostare fuori dalla "procedure TForm1.carCombo" il seguente gruppo di istruzioni:
Codice: [Seleziona]
//---------------------------------------- spostamento suggerito da Forum
type
Ttbpiacon = array of array of string;

const
    ctiCassa: array[0..1, 0..1] of string = (('101001000', '101997999'),     // 1° range conti di Cassa (tabella piancont)
                                      ('101999000', '101999999'));       // ultimo range conti di Cassa (tabella piancont)


    ctiPart: array[0..2, 0..1] of string = (('102000000', '103999999'),  // 1° range conti di contropartita pertinenti a "partmovv" (tabella piancont)
                                            ('105000000', '203999999'),   // 2° range conti di contropartita pertinenti a "partmovv" (tabella piancont)
                                            ('205000000', '999999999')); // ultimo range conti di contropartita pertinenti a "partmovv" (tabella piancont)

    ctiPrest: array[0..1, 0..1] of string = (('104000000', '104999999'),     // 1° range conti di contropartita pertinenti a "prestmom" (tabella piancont)
                                             ('204000000', '204999999'));    // ultimo range conti di contropartita pertinenti a "prestmom" (tabella piancont)
//----------------------------------------           

Mi rendo conto di non avere ancora capito granchè, ma meglio chiedere spiegazioni ora, piuttosto che ricadere negli stessi errori alla prossima occasione.
Titolo: Re:accesso aille tabelle di DB con ZEOS
Inserito da: Stilgar - Aprile 21, 2020, 03:19:21 pm
Ciao
Per rispondere all'ultima domanda, diciamo che per la programmazione ad oggetti è bene fare in quella maniera.
Altrimenti se vuoi fare una procedura che lavori solo su Form1 senza la possibilità di lavorare con altre istanze della TForm1 devi accedere ai suoi campi con l'esplicita indicazione di farlo.Form1.Query1
:)
Stilgar