Delphi:データベースがロックされています(SQLite)
-
21-12-2019 - |
質問
私は2つの問題に直面しています...
(1) Delphi XE6を使用してデータベース(SQLite)に書き込もうとすると、常にデータベースがロックされているエラーメッセージが表示されます。コマンドを使用してアクセスするたびにデータベースを閉じることを確認します。 FDCONNECTION1.CLOSE;
(2) 着信パラメータからテーブルに挿入する方法 次の着信パラメータがあります
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;
.
あらゆるヒントは非常に高く評価されます。事前にありがとうございます。
解決
動的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;
.
ダーティウェイ(Building SQL)
q.SQL.Text:=
'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) VALUES ('+
QuotedStr(Stock_Code) + ', '+
QuotedStr(Stock_Name) + ')';
q.ExecSQL;
.
違いは重要です。汚れた方法は、SQL注入の問題(ほとんどの言語のように、DINAMABLEではなくパラメータなし)を展開します。これはあなたにとって問題になるかもしれません。プロシージャーが独自のコードでのみ個人的に呼び出され、それらの手続きパラメータ値にのみが良い値を含めることができることがわかっている場合、またはSQLを構築して実行する前にいくつかの適切なパラメータチェックを行う場合は...その後安全です。 。
しかし、パラメータ値を知らずに、SQL文がエンジンによって検証されるため、SQL文から自動的に保護されます。そのため、SQLステートメント構造はエンジンによって知られており、実際の値によって変更することはできません。
もう1つの考慮事項は、そのINSERTステートメントをどのくらい頻繁に実行させることです。純粋な方法では、クエリを1回準備して、さまざまなパラメータ値を使用して何度も実行できます(クエリオブジェクトを破棄しないでください。また、SQLプロパティを変更したり、準備メソッドを1回呼び出す必要もあります)。ループ内で頻繁に実行すると、SQLを何度も汚れやすくするよりも効率的になる可能性があります。 Otohあなたが1つの行を挿入する必要がある場合は、もう少しオーバーヘッドを挿入するかもしれません。
==============
脇に... CLは正しいです...それらの値は文字列ではありません。パラメータオブジェクトに異なるデータ型を処理するプロパティが多いことに注意してください。
q.ParamsByName('somedate').AsDateTime := Date;
q.ParamsByName('somenumeric').AsFloat := 3/4;
.
...など。
パラメータを使用しない場合は、物事は困難になります。引用符は文字列に適していますが、日付と通貨やその他の値の種類をSQLに直接書き込みたい場合は、自分がしていることを知る必要があります。あなたは多くの異なる問題に遭遇するかもしれません...そしてあなたのサーバーとのコミュニケーションには良くない、それは世界の反対側にあるかもしれない、またはその方法でフォーマットされた値を読むことができないかもしれません。エンジン固有の書式設定と変換の問題を処理する必要があるかもしれません。
パラメータを使用している場合は、FireDACはあなたのためにこれすべての世話をするべきです。)
他のヒント
クエリに値を取得するには、パラメータを使用します(これはドキュメント):
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;
.
(そして私はこれらすべての値が本当に文字列であるべきであることを疑います...)