Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: petrusic - Gennaio 19, 2024, 04:58:38 pm

Titolo: [Risolto] Controllo integrità database
Inserito da: petrusic - Gennaio 19, 2024, 04:58:38 pm
Per motivi di sicurezza, su cui non mi dilungo, per non tediarvi, ho bisogno di rivedere una mia funzione che mi permette di conoscere, con esattezza. quanti record contiene ciascuna tabella del DB.

Attualmente acquisisco i suddetti valori con le seguenti istruzioni:
Codice: [Seleziona]
 . . .
//---------------------- Estrazione Totale n. record di ciascuna Tabella del DB -------------------------------------------------------------------
      Edit7.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('piancont');
      Edit16.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('causalifreq');
      Edit10.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('ggaperte');
      Edit11.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('movimgg');
      Edit12.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('partmovv');
      Edit13.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('prestmom');
      Edit14.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('racodvoci');
      Edit15.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('restacassagg');
      Edit17.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('riepmovg');
      Edit18.Text:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('componfam');
      Label4.Caption:= IntToStr(numElem);
      numElem:= ContaRecDbTbX('riepnewrecdb');
      Label5.Caption:= IntToStr(numElem);
 . . .
function ContaRecDbTbX(nomeTabDb: String): Integer;

var
  totRecQry: Integer;

  dtPrec, striMia, sql: String;

begin
//----------- Open del DB ------------------------------------------------------
  sql:= 'SELECT * FROM ' + nomeTabDb;
  DataModule1.ZReadOnlyQuery1.Active:= False;
  DataModule1.ZReadOnlyQuery1.SQL.Text:= sql;
  DataModule1.ZReadOnlyQuery1.Active:= True;
  totRecQry:= DataModule1.ZReadOnlyQuery1.RecordCount;
  Result:= totRecQry;
end;                                                                                     
//-------------------------------------------------------------------         

Come si può vedere qui sopra, eseguo ben 11 volte l'accesso alla function che mi permette di ricavare i numeri che mi occorrono.
Ormai, funziona da diverso tempo, ma mi costa, in termini di tempo più di 7 secondi.

Mi pare pesante. Sicuramente sono io che non so sfruttare al meglio le qualità di Lazarus Free Pascal.
Vorrei perciò mettere in pratica un metodo che duri al massimo un battito di ciglia. E' possibile, che qualcuno sappia come?
Titolo: Re:Controllo integrità database
Inserito da: giacomarko - Gennaio 19, 2024, 06:09:39 pm
quesito interessante,

chiaramente hai affrontato il problema in modo lineare, niente da dire, probabilmente avrei fatto lo stesso

ad ogni modo, dato che migliorare si può sempre... ;-)

non e chiaro quale DB usi, ma dipendentemente da questo, ci potrebbero essere funzioni interne inerenti al DB, che potrebbero darti le info che chiedi con una unica query,

a pelle direi che la soluzione dovrebbe essere quella di spostare la ricerca, lato DB

in MySQL con la keyword UNION, potresti ottenere quello che cerchi in un unica esecuzione, ammesso che il tuo DB lo contempli

prova a verificare quì

https://www.google.com/amp/s/rosariociaglia.altervista.org/mysql-come-contare-le-righe-di-una-o-piu-tabelle/amp/

Titolo: Re:Controllo integrità database
Inserito da: DragoRosso - Gennaio 19, 2024, 09:01:43 pm
Vado così a memoria, ma su una ZTable ci dovrebbe essere la proprietà RecordCount ....

Se usi le tabelle, oltre alle query, hai già il numero di record.

Ciao
Titolo: Re:Controllo integrità database
Inserito da: giacomarko - Gennaio 20, 2024, 12:07:29 am
ricordi bene,

anche se alla fine o con una query o interrogando direttamente i dataset, alla fine fai la stessa cosa, chiedi quanti record ci sono ad ogni singola tabella...

bisognerebbe imbastire un test e misurare i tempi via SQL vs i tempi via dataset...

se la funzione UNION gira, fai tutto in un colpo, con un unico accesso
Titolo: Re:Controllo integrità database
Inserito da: nomorelogic - Gennaio 20, 2024, 10:44:38 am
penso che il modo più veloce sia quello di chiedere direttamente al database in un unico colpo (come suggerito da giacomarko)
prova ad eseguire questa query sul db, è abbastanza standard e dovrebbe funzionare ovunque
quando ti funziona eseguila da Lazarus
sono convinto che la velocità di esecuzione sarà la migliore possibile

Codice: [Seleziona]
select * from (
   select 'tabella1' as nome, count(*) as conta from tabella1
   union
   select 'tabella2' as nome, count(*) as conta from tabella2
   union
   select 'tabella3' as nome, count(*) as conta from tabella3
   union
   select 'tabella4' as nome, count(*) as conta from tabella4
) as contarecord


nomorelogic



Edit:
sul alcuni server forse devi sostituire "union" con "union all"
da provare
Titolo: Re:Controllo integrità database
Inserito da: petrusic - Gennaio 20, 2024, 05:24:36 pm
non e chiaro quale DB usi.
Hai ragione. L'avevo indicato, ma nel correggere il contenuto, l'ho cancellato, involontariamente.
Io uso  SQLite3, l'unico che conosco un pò.

penso che il modo più veloce sia quello di chiedere direttamente al database in un unico colpo (come suggerito da giacomarko)
prova ad eseguire questa query sul db, è abbastanza standard e dovrebbe funzionare ovunque
quando ti funziona eseguila da Lazarus
Codice: [Seleziona]
select * from (
   select 'tabella1' as nome, count(*) as conta from tabella1
   union
   select 'tabella2' as nome, count(*) as conta from tabella2
   union
   select 'tabella3' as nome, count(*) as conta from tabella3
   union
   select 'tabella4' as nome, count(*) as conta from tabella4
) as contarecord
Ho provato la query in DB-BRowser e funziona.

L'ho provata, poi in Lazarus, ma non funziona. L'ho ridotta anche ad una sola riga, ma non funziona lo stesso.

Codice: [Seleziona]
sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) as conta from causalifreq';
  sql:= sql + 'UNION select "componfam" as nomeTbx, count(*) as conta from componfam) as contarec';
  DataModule1.ZReadOnlyQuery1.Active:= False;
  DataModule1.ZReadOnlyQuery1.SQL.Text:= sql;
  DataModule1.ZReadOnlyQuery1.Active:= True;        <------ quando viene eseguita questa istruzione da'  "ERRORE LOGICO"
  DataModule1.ZReadOnlyQuery1.First;
  while not DataModule1.ZReadOnlyQuery1.EOF do

Ho provato, infine, a disattivare la riga, ma produce un Errore per Dataset inattivo.
Titolo: Re:Controllo integrità database
Inserito da: bonmario - Gennaio 20, 2024, 05:31:21 pm
Codice: [Seleziona]
sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) as conta from causalifreq';
  sql:= sql + 'UNION select "componfam" as nomeTbx, count(*) as conta from componfam) as contarec';

La seconda riga, deve diventare
Codice: [Seleziona]
  sql:= sql + ' ' + 'UNION select "componfam" as nomeTbx, count(*) as conta from componfam) as contarec';

In pratica, devi mettere uno spazio prima di "union".
Così come hai fatto tu, la parola "causalifreq" della riga precedente, la stai attaccando alla parola "union" della riga successiva, ed ottieni "causalifreqUNION" tutto attaccato !!

Ciao, Mario
Titolo: Re:Controllo integrità database
Inserito da: petrusic - Gennaio 20, 2024, 07:42:21 pm
Codice: [Seleziona]
sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) as conta from causalifreq';
  sql:= sql + 'UNION select "componfam" as nomeTbx, count(*) as conta from componfam) as contarec';

La seconda riga, deve diventare
Codice: [Seleziona]
  sql:= sql + ' ' + 'UNION select "componfam" as nomeTbx, count(*) as conta from componfam) as contarec';

In pratica, devi mettere uno spazio prima di "union".
Così come hai fatto tu, la parola "causalifreq" della riga precedente, la stai attaccando alla parola "union" della riga successiva, ed ottieni "causalifreqUNION" tutto attaccato !!

Ciao, Mario

Grazie Mario. Hai ragione, mi era sfuggito. L'ho modificata, ma non funziona lo stesso. C'è un errore di sintassi che io NON riesco a capire.
Ecco le righe con la correzione che mi hai suggerito:
Codice: [Seleziona]
 sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) AS conta from causalifreq';
 sql:= sql + ' UNION select "componfam" as nomeTbx, count(*) AS conta from componfam) AS contarec';
  WriteLn('sql= |' + sql + '|');
  DataModule1.ZReadOnlyQuery1.Active:= False;
  DataModule1.ZReadOnlyQuery1.SQL.Text:= sql;
  DataModule1.ZReadOnlyQuery1.Active:= True;                                                                       
Per mia tranquillità, riporto anche l'ìesito del comando
Citazione
sql= |select * from (select "causalifreq" AS nomeTbx, count(*) AS conta from causalifreq UNION select "componfam" as nomeTbx, count(*) AS conta from componfam) AS contarec|
Titolo: Re:Controllo integrità database
Inserito da: nomorelogic - Gennaio 20, 2024, 11:50:28 pm
l'sql usa l'apice singolo per delimitare le stringhe e non il doppio apice
per questo il risultato della writeln deve essere:
Codice: [Seleziona]
sql= |select * from (select 'causalifreq' AS nomeTbx, count(*) AS conta from causalifreq UNION select 'componfam' as nomeTbx, count(*) AS conta from componfam) AS contarec|

per ottenere un apice singolo in una stringa pascal bisogna fare l'escape con un altro apice singolo
se usi questa stringa su DB-BRowser vedrai che funziona mentre quella che pai postato tu (con il doppio apice), ti darà errore

ora non riesco a provare ma le istruzioni seguenti dovrebbero essere corrette
notare che solo select ci sono 2 apici singoli e non un doppio apice
e così anche a seguire
Codice: [Seleziona]
sql:= 'select * from (select ''causalifreq'' AS nomeTbx, count(*) AS conta from causalifreq';
sql:= sql + ' UNION select ''componfam'' as nomeTbx, count(*) AS conta from componfam) AS contarec';

Titolo: Re:Controllo integrità database
Inserito da: petrusic - Gennaio 21, 2024, 10:13:50 am
l'sql usa l'apice singolo per delimitare le stringhe e non il doppio apice
per questo il risultato della writeln deve essere:
Codice: [Seleziona]
sql= |select * from (select 'causalifreq' AS nomeTbx, count(*) AS conta from causalifreq UNION select 'componfam' as nomeTbx, count(*) AS conta from componfam) AS contarec|

per ottenere un apice singolo in una stringa pascal bisogna fare l'escape con un altro apice singolo
se usi questa stringa su DB-BRowser vedrai che funziona mentre quella che pai postato tu (con il doppio apice), ti darà errore

Purtroppo devo dirti che le prove fatte prima di postare hanno dimostrato che lo SQL non si arrabbia di fronte al doppio apice. Allego un'ulteriore prova fatta stamani in DB-Browser. Come puoi vedere, NON da' Errore.

Comunque, siccome bisogna percorrere tutte le strade possibili, fino a trovare quella giusta, ho provato anche a mettere i 2 apici singoli dentro la stringa sql: Ebbene, NON hanno funzionato, nè DB-Browser, nè Lazarus.

Titolo: Re:Controllo integrità database
Inserito da: petrusic - Gennaio 21, 2024, 03:51:45 pm
Allora, ho fatto un buon passo avanti.

Ho rivisto le istruzioni inserite e mi sono ricordato che, dopo avere stabilito quale database cosiderare come DB corrente, devo dare a Zeos l'indirizzo del DB ed attivarne la connessione.

Poichè il controllo che ho inserito va posto a, monte, prima di qualsiasi altra operazione sul DB, avrei dovuto spostare anche le istruzioni:
Codice: [Seleziona]
DataModule1.ZConnection1.Database:= dbCorr;
DataModule1.ZConnection1.Connected:= True; 

Dopo avere impostato correttamente le suddette istruzioni, ho ripetuto la query suggerita da nomorelogic :
Codice: [Seleziona]
  sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) AS conta from causalifreq';
  sql:= sql + ' UNION select "componfam" as nomeTbx, count(*) AS conta from componfam';
  sql:= sql + ' UNION select "ggaperte" as nomeTbx, count(*) as conta from ggaperte';
  sql:= sql + ' UNION select "movimgg" as nomeTbx, count(*) as conta from movimgg) AS contarec'; 

e, con soddisfazione, ho visto che l'errore è finalmente scomparso.

Mi resta ancora di farmi restituire da Zeos i totali delle singole tabelle.

Pensando che potessi comportarmi come quando estraggo il contenuto mdi un campo del DB, ho scritto di brutta :
Codice: [Seleziona]
  i:= 0;
  sql:= 'select * from (select "causalifreq" AS nomeTbx, count(*) AS conta from causalifreq';
  sql:= sql + ' UNION select "componfam" as nomeTbx, count(*) AS conta from componfam';
  sql:= sql + ' UNION select "ggaperte" as nomeTbx, count(*) as conta from ggaperte';
  sql:= sql + ' UNION select "movimgg" as nomeTbx, count(*) as conta from movimgg) AS contarec';
  DataModule1.ZReadOnlyQuery1.Active:= False;
  DataModule1.ZReadOnlyQuery1.SQL.Text:= sql;
  DataModule1.ZReadOnlyQuery1.Active:= True;
  DataModule1.ZReadOnlyQuery1.First;
  while not DataModule1.ZReadOnlyQuery1.EOF do
  begin
    tbDBintegro[i, 1]:= DataModule1.ZReadOnlyQuery1.FieldByName('conta').AsString;
    DataModule1.ZReadOnlyQuery1.Next;
    i:= i + 1;
  end;

Come mi aspettavo, si è manifestato un nuovo Errore, ma, pur avendo cercato, non ho trovato l'esempio che mi riguarda.
Titolo: Re:Controllo integrità database
Inserito da: petrusic - Gennaio 21, 2024, 04:14:17 pm
Ho capito perchè non funzionava.
Ho inserito l'inizializzazione dell'indice dell'array ed ecco il risultato:
Citazione
tbDBintegro[0, 0]= "causalifreq"
tbDBintegro[0, 1]= "570"
tbDBintegro[1, 0]= "componfam"
tbDBintegro[1, 1]= "6"
tbDBintegro[2, 0]= "ggaperte"
tbDBintegro[2, 1]= "64"
tbDBintegro[3, 0]= "movimgg"
tbDBintegro[3, 1]= "66547"
tbDBintegro[4, 0]= "prestmom"

Mi pare un bellissimo risultato. Mi dispiace solo non aver capito prima cosa mancava a Zeos per non potere eseguire la query Union.

Avrei risparmiato anche voi tutti.

Grazie ancora  ;D
Titolo: Re:[Risolto] Controllo integrità database
Inserito da: nomorelogic - Gennaio 22, 2024, 09:29:55 am
ottimo risultato
puoi dirci qualcosa sui tempi di esecuzione?
Titolo: Re:[Risolto] Controllo integrità database
Inserito da: petrusic - Gennaio 22, 2024, 03:46:52 pm
ottimo risultato
puoi dirci qualcosa sui tempi di esecuzione?
Non c'è dubbio che è tutta un'altra cosa.
Il caricamento nella tabella di memoria avviene all'istante.
 ;)