Domanda

Sto affrontando due problemi ...

(1) Quando provo a scrivere su un database (SQLite) utilizzando Delphi XE6, ottengo sempre il database è il messaggio di errore bloccato.Sono certo che chiudo il database ogni volta che l'ho accettato usando il comando Fdconnection1.close;

(2) Come posso inserire in una tabella dai parametri in entrata? Ho i seguenti parametri in arrivo

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);
.

e ha provato a scrivere nella tabella con il seguente comando SQL:

sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell,
         Price_Per_Share, Num_Shares, Trans_Fee) 
         VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share,  
         Num_Shares, Trans_Fee)';
.

Ma non sembra funzionare ...

Di seguito è riportata la procedura completa che sto avendo problemi con

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
  Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);
var
  query : TFDQuery;
  sSQL: string;
begin
    query := TFDQuery.Create(nil);
  try
    ConnectToSQLite;
    query.Connection := FDConnection1;
  if Stock_Code.IsEmpty then
    ShowMessage('Stock Code Cannot Be Empty')
    else
      if Stock_Name.IsEmpty then
        ShowMessage('Stock Name Cannot Be Empty')
        else
          if Tran_Date.IsEmpty then
            ShowMessage('Transaction Date Cannot Be Empty')
            else
            begin
//              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee)';
              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (1,2,3,4,5,6,7)';
              query.sql.Text := sSQL;
              query.ExecSQL;
              query.Open();
        end;
  finally
    query.Close;
    query.DisposeOf;
    DisconnectFromSQLite;
  end;

end;
.

Qualsiasi suggerimento sarà molto apprezzato.Grazie in anticipo.

È stato utile?

Soluzione

Ci sono due tecniche per eseguire un'istruzione SQL dinamica. Ma userò un SQL più breve, per concentrarmi sulla logica:

il modo puro (usando i parametri)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) '+
  'VALUES (:Stock_Code, :Stock_Name)';
q.Prepare; //Optional
q.ParamsByName('Stock_Code').AsString := Stock_Code;
q.ParamsByName('Stock_Name').AsString := Stock_Name;
q.ExecSQL;
.

il modo sporco (edificio sql)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) VALUES ('+
  QuotedStr(Stock_Code) + ', '+
  QuotedStr(Stock_Name) + ')';
q.ExecSQL;
.

Le differenze sono significative. Il modo sporco ti espone ai problemi di iniezione SQL (come nella maggior parte delle altre lingue, quando si costruisce SQL dinamicamente ma senza parametri). Questo potrebbe essere o non essere un problema per te. Se si sa che la procedura viene chiamata solo in privato dal proprio codice e che i valori dei parametri di procedura possono contenere solo valori buoni ... o se si esegue un buon funzionamento del parametro prima di costruire ed eseguire il tuo SQL ... Allora sei al sicuro .

Ma se lo fai con i parametri (il modo puro) si è protetti automaticamente dall'iniezione SQL, poiché l'istruzione SQL viene convalidata dal motore, senza conoscere i valori dei parametri. Quindi la struttura dell'istruzione SQL è nota dal motore e non può essere modificata dai valori effettivi.

Un'altra considerazione è quanto frequentemente eseguirai questa dichiarazione di inserimento. Il modo puro consente di preparare la query una volta, ed eseguirlo molte volte con valori dei parametri diversi (non è necessario distruggere l'oggetto query, né modificare la proprietà SQL, e devi chiamare il metodo preparato una volta). Se lo esegui frequentemente all'interno di un ciclo, può essere più efficiente di costruire la SQL molte volte il modo sporco. OTOH Se hai solo bisogno di inserire una singola riga, può posare un po 'più in alto.

=================

Come a parte ... CL è giusto ... quei valori non dovrebbero essere stringhe. Tieni presente che l'oggetto dei parametri ha molte proprietà per gestire diversi tipi di dati:

  q.ParamsByName('somedate').AsDateTime := Date;
  q.ParamsByName('somenumeric').AsFloat := 3/4;
.

... e così via.

Se non usi i parametri, le cose diventano difficili. La funzione quotestr è buona per le stringhe, ma se si desidera bruciare date e valute e altri tipi di valore direttamente nel tuo SQL, devi sapere cosa stai facendo. È possibile che si verifichino molti problemi diversi ... impostazioni specifiche o in formato locale che non sono buone per essere comunicanti con il server, che potrebbe essere sull'estremità opposta del mondo, o potrebbe semplicemente non essere in grado di leggere i valori formattati in questo modo. Potrebbe essere necessario gestire i problemi di formattazione e conversione specifici del motore.

Se usi i parametri, allora FireDac dovrebbe prenderti cura di tutto questo per te;)

Altri suggerimenti

Per ottenere valori nella query, utilizzare i parametri (questo è spiegato il Documentazione ):

query.SQL.Text := 'INSERT INTO Each_Stock_Owned'+
                    '(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, '+
                     'Price_Per_Share, Num_Shares, Trans_Fee) '+
                    'VALUES (:sc, :sn, :td, :bs, :pps, :ns, :tf)';
query.ParamByName('sc').AsString := Stock_Code;
query.ParamByName('sn').AsString := Stock_Name;
query.ParamByName('td').AsString := Tran_Date;
query.ParamByName('bs').AsString := Buy_Sell;
query.ParamByName('pps').AsString := Price_Per_Share;
query.ParamByName('ns').AsString := Num_Shares;
query.ParamByName('tf').AsString := Trans_Fee;
query.ExecSQL;
.

(E dubito che tutti questi valori siano davvero dovrebbero essere stringhe ...)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top