Delphi/400のシステム実行時に、エラー発生時などの原因調査のため
更新SQLの実行ログを取得されている場合があるかと存じます。
そこで更新のSQL文にパラメータ(バインド変数)を使用していると、
どのような値を更新したのかがSQL文中には残りません。
<例>
バインド変数不使用(SQL文に直接更新値を記述する)
INSERT INTO FILEAA (XX0001, XX0002, XX0003) VALUES ('XXTEST', 20250430, 'TEST0000001')
バインド変数使用(SQL文に直接更新値を記述しない)
INSERT INTO FILEAA (XX0001, XX0002, XX0003) VALUES (:XX0001, :XX0002, :XX0003)
(後続のロジックでパラメータの値をセット)
今回はこうしたパラメータを
Queryコンポーネントから取得するテクニックを紹介します。
SQL発行時に渡したパラメータの取得
プログラムはSQL文をそのまま渡しており、
バインド変数はパラメータとして渡しているため、
SQL文内だけでパラメータの値まで確認する方法は残念ながら存在しません。
しかし、渡されたパラメータの情報を取得することは可能ですので、
Paramsの値を使用して、SQL文とは別にパラメータやバインド変数の
一覧を取得し、ログに残すことは可能です。
具体的には、対象の更新SQLをExecSQLで発行する前または後に、
以下の例のように記述します。
※型を取得するにあたり、uses節に「System.TypInfo」が必要です。
※qry=TSQLQuery・TFDQueryどちらでも動作します。
※この例ではパラメータの値をTMemoに転送しています。
※この例ではすべてのパラメータの値を取得するため、WHERE句で使用したパラメータも取得します。
var
i: Integer;
sTEMP: String;
begin
// ※ここに元々のロジック(SQL文やパラメータのセットなど)※
Memo1.Lines.Clear; // 初期化
Memo1.Lines.Add(qry.SQL.Text); // 最初にSQL文をセット
for i := 0 to (qry.Params.Count - 1) do
begin
Memo1.Lines.Add(''); // 空行を追加
sTEMP := IntToStr(i) + ':' + qry.Params[i].Name;
sTEMP := sTEMP + ':' + GetEnumName(TypeInfo(TFieldType), Ord(qry.Params[i].DataType));
Memo1.Lines.Add(sTEMP); // パラメータの要素番号と名前と型を追加
sTEMP := qry.Params[i].AsString;
Memo1.Lines.Add(sTEMP); // パラメータの値(文字型に変換)を追加
end;
// ※ここに元々のロジック(ExecSQLなど)※
end;
<実行結果イメージ>
上記のロジックを使ってMemo1.Linesに出力されるテキストは以下のようなイメージになります。
(最初にSQL文を、1行空けて各パラメータの要素番号・名前・型・値をセット)
UPDATE TESTLIB/YCTEST SET YC0004 = :YC0004, YC0005 = :YC0005, YC0006 = :YC0006, YC0014 = :YC0014, YC0021 = :YC0021 WHERE YC0001 = :YC0001 AND YC0002 = :YC0002
0:YC0004:ftString
テスト文字列305
1:YC0005:ftString
テスト文字列
2:YC0006:ftInteger
305
3:YC0014:ftDateTime
2025/05/23 15:35:22
4:YC0021:ftString
NSCO
5:YC0001:ftString
BBTEST
6:YC0002:ftInteger
20250523
発展編:配列DML使用時のパラメータの取得
1回のSQLで受け渡しできるパラメータ数の上限は1040個です。
またSQL文の長さにも上限があります。
(※FireDAC:約16000byte、dbExpress/BDE:約32000byte)
FireDAC接続においてはこれらの制約を解決するため、
配列DMLを使ってパラメータを配列化して更新することが可能になっています。
(配列DMLの詳細についてはこちらのTipsから)
このとき、配列DMLの各パラメータの値を取得したい場合は
以下のようにロジックを記述することが可能です。
TFDQueryのParams.ArraySizeが更新する行数となります。
※型を取得するにあたり、uses節に「System.TypInfo」が必要です。
※qry=TSQLQuery・TFDQueryどちらでも動作します。
※この例ではパラメータの値をTMemoに転送しています。
※この例ではすべてのパラメータの値を取得するため、WHERE句で使用したパラメータも取得します。
var
i, j: Integer;
sTEMP: String;
begin
// ※ここに元々のロジック(SQL文やパラメータのセットなど)※
Memo1.Lines.Clear; // 初期化
Memo1.Lines.Add(qry.SQL.Text); // 最初にSQL文をセット
for i := 0 to (FDQuery1.Params.ArraySize - 1) do // i = 各行(更新する行数ぶん)
begin
for j := 0 to (FDQuery1.Params.Count - 1) do // j = 1行あたりの各パラメータ
begin
Memo1.Lines.Add(''); // 見やすくするため空行を追加
sTEMP := IntToStr(i) + '-' + IntToStr(j) + ':' + FDQuery1.Params[j].Name;
sTEMP := sTEMP + ':' +
GetEnumName(TypeInfo(TFieldType), Ord(FDQuery1.Params[j].DataType));
Memo1.Lines.Add(sTEMP); // パラメータの行数・要素番号と名前と型を追加
sTEMP := FDQuery1.Params[j].AsStrings[i];
Memo1.Lines.Add(sTEMP); // パラメータの値(文字型に変換)を追加
end;
end;
// ※ここに元々のロジック(Executeなど)※
end;
関連記事: