Newsgroup: it.comp.lang.delphi
Titolo: TSQLQuery e parametri

Eccomi con un nuovo problema con Delphi2010 e dbexpress.
Se definisco un comando SQL formattando il comando con la funzione 
fomrat e senza usare i parametri della query, tutto funziona perfettamente.
Se invece provo a usare i parametri, ottengo un errore, che varia a 
seconda delle prove che faccio.
Non riesco a capire come si deve preparare la query e i suoi parametri 
affinche` la chiamata a ExecSql funzioni.
Quanto segue e` una delle prove:
   q:=TSQLQuery.Create(nil);
   try
     q.SQLConnection:=SQLConnection; (collegato a un db firebird)
     q.ParamCheck := True;
     q.SQL.Add('INSERT INTO LANGUAGES (ID_LANGUAGE, SHORT_NAME) VALUES 
(1, :SHORT_NAME)');
     q.Params.ParamByName('SHORT_NAME').AsString := 'Test';
     SqlConnection.StartTransaction(TD);
     try
       q.ExecSQL(False);
       Commit(TD);
     except
       Rollback(TD);
     end;
   finally
     q.Close;
     q.Free;
Ho provato ad aggiungere cose come PrepareStatement, Prepared:=True, 
Bound:=False, Bound:=True; ecc.
Ho letto tutto quello che ho trovato in rete e i consigli sono piu` o 
meno sempre quelli, pero` qui non funzionano.
Dove sbaglio?
Enrico

DoctorC ha pensato forte :

Che errori?
Commit(TD) e Rollback(TD) penso siano sqlconnection.commit(td) e 
sqlconnection.rollback(Td)
Kd


Si, naturalmente.
Il problema e` nel passaggio dei parametri.
Non riesco a fare in modo che il comando SQL venga formattato.
A seconda dei tentativi ho vari errori, che piu` o meno indicano che il 
parametro e` sconosciuto o non valido.
Prima di eseguire ExecSql, il comando sql ha ancora il  nome del 
parametro e non il valore. E` normale?
Potete darmi un esempio di come configurare ed eseguire una query con 
parametri (usando Params) a run time per inserire un record in un db 
firebird usando dbexpress?
Enrico

> Enrico
SqlSpese -->' TSqlDataset
SqlSp --> TSQLStoredProc
  sSql := 'INSERT INTO TB_SPESE ' +
         '(ID, ID_UTENTE, ID_CODICE, DATA, ENTRATA, USCITA, SALDO, NOTE, 
OLD_CODICE)' +
          ' VALUES (:Id, :Utente, :Codice, :Data, :Entrata, :Uscita, :Saldo, 
' +
          ':Note, :OldCodice)';
  //calcola progressivo
  SqlSp_Spese.StoredProcName := 'CON_TB_SPESE_ID';
  SqlSp_Spese.ExecProc;
  //assegna parametri Query
  Sql_Spese.Params.ParamByName('Id').AsInteger := 
SqlSp_Spese.Params[0].Value;
  Sql_Spese.Params.ParamByName('Utente').AsInteger := iUtente;
  Sql_Spese.Params.ParamByName('Codice').AsInteger := iCodSpesa;
  Sql_Spese.Params.ParamByName('Data').AsDate := dData;
  Sql_Spese.Params.ParamByName('Entrata').AsCurrency := cEntrata;
  Sql_Spese.Params.ParamByName('Uscita').AsCurrency := cUscita;
  Sql_Spese.Params.ParamByName('Saldo').AsCurrency := cSaldo;
  Sql_Spese.Params.ParamByName('Note').AsString := sNote;
  Sql_Spese.Params.ParamByName('OldCodice').AsInteger := iOldCodice;
  //Esegue Query Inserimento
  Sql_Spese.ExecSQL;
  //Esegue Transazione
  frm_ConnettiFb.ConfermaOperazione;
procedure Tfrm_ConnettiFb.ConfermaOperazione;
var TD: TTransactionDesc;
begin
  TD.TransactionID := 1;
  TD.IsolationLevel := xilREADCOMMITTED;
  SQLConnection1.StartTransaction(TD);
  try
    SQLConnection1.Commit(TD);
  except
    SQLConnection1.Rollback(TD);
  end;
end;
function Tfrm_ConnettiFb.ConnettiDataBase(var NomeDataBase: string): string;
var bTransactionOK:Boolean;
begin
  try
    SQLConnection1.Params.Values['DataBase'] := NomeDataBase;
    SQLConnection1.Params.Values['User_Name'] := 'sysdba';
    SQLConnection1.Params.Values['password'] := 'masterkey';
    SQLConnection1.LoginPrompt := False;
    SQLConnection1.Connected := True;
    Result := 'OK'
  except
    on e:exception do
    Result:= e.Message;
  end;
 // Vertifica se supportate Transazioni
 if SQLConnection1.TransactionsSupported then bTransactionOK:=True
 else bTransactionOK:=False;
end;

W dniu 2010-12-07 06:05, Maurizio pisze:

Non vedo differenze rispetto a quello che faccio io.
Non usi PrepareStatement?
Grazie per l'esempio.
Faro` ancora delle prove oggi...
Enrico

 Enrico
Ci ho messo un po' ma alla fine ho trovato la differenza.
Io eseguo ExecSql con un parametro mentre Maurizo lo esegue senza parametri.
Tolto il parametro tutto funziona :) 2 giorni buttati...
Avevo letto l' help di Embarcadero e mi sembrava di aver capito che ci 
volesse il parametro...
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SqlExpr_TSQLQuery_ExecSQL.html
Grazie per l' aiuto
A presto
Enrico

Se scrivo questa:
select * from tabella where campo1=:avalore1 and campo2=:valore2
ogni volta che tento la stessa query con parametri diversi, molti db,
oracle in testa, hanno un sistema di caching che permette di
riutilizzare uno statement sql precedentemente utilizzato con
parametri diversi.
Viceversa, se i parametri non ci sono e i relativi valori sono
cablati, avrai n query diverse, una per ogni coppia di valori usati
nella where.
Questa cosa alla lunga impatta sulle performance.
Parlo ovviamente di query...Se si tratta di stored procedure esse sono
gia' compilate, salvo l'essere in qualche modo non valide...
Ergo: non usare query parametriche potrebbe non essere una buona idea.
Tratto dalla guida di d7e:
Delphi syntax:
function ParseSQL(SQL: String; DoCreate: Boolean): String;
C++ syntax:
AnsiString __fastcall ParseSQL(AnsiString SQL, bool DoCreate);
Description
Call ParseSQL to replace all the parameters in the SQL statement
passed as SQL with question marks (?). ParseSQL
********* recognizes parameters by a preceding colon (:).
*****************
Double colons (::) or colons contained in quoted strings are parsed as
literals, and the immediately following name is not replaced with a
question mark. The converted SQL statement is returned.
If the DoCreate parameter is true, all parameters in the Items
property are replaced with a set of TParam objects whose names are the
same as the strings removed from the SQL statement.
For example, given the SQL string
SELECT * FROM EMPLOYEES
WHERE (ID = :EMP_ID) AND (NAME = :EMP_NAME)
ParseSQL returns the string
SELECT *
FROM EMPLOYEES
WHERE (ID = ?) AND (NAME = ?)
and, if DoCreate is true,
***** the Items property contains two TParam objects with the names
EMP_ID and EMP_NAME *****
A.