SQL スクリプトに関する質問(FireDAC)
FAQ(FireDAC) への移動
このトピックでは、SQL スクリプトの実行に関係する質問と回答の一覧を扱います。
Q1: クエリの末尾にセミコロンを使用できないのはなぜですか。クエリからセミコロンを取り除けば、うまくいきます。
A: 多くの SQL スクリプト ダイアレクトでは、";" は SQL コマンドの区切り記号で、SQL 言語の一部ではありません。SQL コマンドの末尾に ";" を使用できる DBMS もあれば、そうでない DBMS もあります。つまり、ただ ";" を削除すればよいのです。
Q2: 一部の DBMS(PostgreSQL、Oracle、Firebird)では、SQL 文を 1 つしか実行できませんが、SQLite では複数の SQL 文を同時に実行できます。それはなぜでしょうか。
A: 設計上そうなっているのです。ExecSQL メソッドでは 1 つの SQL コマンドを DBMS API にそのまま渡します。DBMS で "バッチ" クエリがサポートされている場合は、そのクエリが実行され、そうでない場合はクエリが失敗します。TFDScript では、複数の SQL コマンドとスクリプト制御コマンドを含んだ SQL スクリプトを実行できます。
Q3: たとえ複数のスクリプトがあっても、ExecuteAll では、最初のスクリプトしか実行されません。
A: 最初のスクリプトは "ルート" スクリプトです。他のスクリプトを実行するには、それらを "ルート" スクリプトから明示的に呼び出さなければなりません。以下に例を示します。
with FDScript1.SQLScripts do begin
with Add do begin
Name := 'root';
SQL.Add('@first'); // explicitly call 'first' script
SQL.Add('@second'); // explicitly call 'second' script
end;
with Add do begin
Name := 'first';
SQL.Add('create table t1 ...;');
SQL.Add('create table t2 ...;');
end;
with Add do begin
Name := 'second';
SQL.Add('create procedure p1 ...;');
SQL.Add('create procedure p2 ...;');
end;
end;
ExecuteStep では、次のスクリプト コマンドを TFDScript.Position の位置から実行します。ExecuteAll では、スクリプトを全部実行します。また、ValidateAll や ValidateStep もあります。これらのメソッドでは、スクリプトは処理されますが、SQL コマンドは実行されません。ValidateAll の呼び出しで TFDScript.TotalJobSize に値が割り当てられます。そのため、次の ExecuteAll 呼び出しで TFDScript.TotalPct10Done が正しく更新されます。これは、処理されるスクリプト コマンドの 10% です。
Q4: SQL 文(コマンド)ごとに FDConnection.ExecSQL を実行する場合と FDScript.ExecuteAll を実行する場合とで、パフォーマンスに違いがありますか。
A: これらの各メソッドの裏にある SQL 実行コードは同じです。どちらも IFDPhysCommand.Execute メソッドを使用しています。
TFDScript パーサーは高度に最適化されており、Oracle PL/SQL(コマンドの途中で ";" を使用可能)などの多くの SQL ダイアレクトを認識します。このパーサーにより、正確かつ柔軟な制御が可能になります。
そのため、FDConnection.ExecSQL にコマンドを 1 つずつ送信し、かつ、これらのコマンドをスクリプトなどから抽出する必要がない場合は、FDConnection.ExecSQL が最速の方法になります。SQL スクリプトがファイルに記述されている場合は、FDScript.ExecuteAll が最速の方法になります。
Q5: スクリプトの処理に失敗した場合、それをロールバックするには、どうすればよいでしょうか。
A: 1) FireDAC のトランザクション制御を使用する方法:
FDConnection1.StartTransaction;
try
FDScript1.ExecuteAll;
FDConnection1.Commit;
except
FDConnection1.Rollback;
raise;
end;
2) Oracle の場合は PL/SQL ブロックを、その他の DBMS の場合は類似の構文要素を使用する方法:
begin
insert into u_btk.t_test values (1, sysdate);
insert into u_btk.t_test values (2, sysdate);
insert into u_btk.t_test values (1, sysdate);
commit;
exception
when others then
rollback;
raise;
end;
3) TFDScript.OnError を使用する方法:
procedure TForm1.FDScript1Error(ASender: TObject;
const AInitiator: IFDStanObject; var AException: Exception);
begin
FDConnection1.Rollback;
end;
Q6: Firebird で以下のスクリプトを実行すると、"コマンドの 3 行目の終わりが正しくありません" というエラーが発生します。これを解決するには、どうすればよいでしょうか。
EXECUTE BLOCK
AS
DECLARE VARIABLE MYVAR VARCHAR(250);
BEGIN
...
END;
A: ブロックを含んだスクリプトを実行するには、ブロックの前でコマンド区切り記号を変更し、必要に応じて、ブロックの後でそれを元に戻さなければなりません。以下に例を示します。
SET TERM #;
EXECUTE BLOCK
...
END;
#
SET TERM ;#