2

私は2つの問題に直面しています...

(1) Delphi XE6 を使用してデータベース (SQLite) に書き込もうとすると、常にデータベースがロックされているというエラー メッセージが表示されます。コマンド FDConnection1.Close を使用してデータベースにアクセスするたびに、データベースを閉じることは確実です。

(2) 入力パラメータからテーブルに INSERT INTO するにはどうすればよいですか? 次の着信パラメータがあります

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

次の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)';

しかし、うまくいかないようです...

以下は、私が問題を抱えている完全な手順です

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;

どんなヒントでも大歓迎です。前もって感謝します。

4

2 に答える 2

7

動的 SQL ステートメントを実行するには、2 つの方法があります。ただし、ロジックに集中するために、より短い SQL を使用します。

純粋な方法 (パラメーターを使用)

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;

汚れた方法 (SQL の構築)

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

違いは重要です。汚い方法では、SQL インジェクションの問題にさらされます (他のほとんどの言語と同様に、SQL を動的に構築するがパラメーターを使用しない場合)。これはあなたにとって問題になる場合とそうでない場合があります。プロシージャが独自のコードによってのみ非公開で呼び出され、それらのプロシージャのパラメーター値に適切な値しか含めることができないことがわかっている場合、または SQL を構築して実行する前に適切なパラメーター チェックを行っている場合は、安全です。 .

ただし、パラメーターを使用して (純粋な方法で) 実行すると、SQL ステートメントがエンジンによって検証されるため、パラメーター値を知らなくても、SQL インジェクションから自動的に保護されます。そのため、SQL ステートメントの構造はエンジンによって認識され、実際の値によって変更することはできません。

もう 1 つの考慮事項は、その INSERT ステートメントを実行する頻度です。純粋な方法では、クエリを 1 回準備し、さまざまなパラメーター値で何度も実行できます (クエリ オブジェクトを破棄したり、SQL プロパティを変更したりしてはならず、Prepare メソッドを 1 回呼び出す必要があります)。ループ内で頻繁に実行すると、汚い方法で何度も SQL を構築するよりも効率的になります。OTOH 1行だけ挿入する必要がある場合は、オーバーヘッドが少し増える可能性があります。

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

余談ですが... CLは正しいです...これらの値は文字列であってはなりません。Parameter オブジェクトには、さまざまなデータ型を処理するための多くのプロパティがあることに注意してください。

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

... 等々。

パラメータを使用しないと、事態が難しくなります。QuoteStr 関数は文字列に適していますが、日付、通貨、およびその他の値の型を SQL で直接書き込みたい場合は、何をしているのかを知る必要があります。さまざまな問題が発生する可能性があります...ロケール固有の設定またはフォーマット設定がサーバーとの通信に適していない場合、世界の反対側にある場合や、そのようにフォーマットされた値を読み取れない場合があります。エンジン固有のフォーマットおよび変換の問題を処理する必要がある場合があります。

パラメータを使用する場合は、FireDAC がすべての処理を行います ;)

于 2014-07-31T07:33:38.397 に答える