Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi/400】SQL実行時に渡すパラメータの一覧を取得するテクニック

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;

 

 

 
関連記事: