メニューボタン
IBMi海外記事2021.02.10

SQLにCLコマンドを書かせる

Ted Holt 著

SQLは、私にとって仕事に不可欠なツールです。SQLがなかったら、私はトラック運転手に転職するでしょう。当然のことながら、私は、SQLをうまく使うための手法を1つでも多く、常に探し求めています。この記事では、最近、SQLを使用して私に代わって巨大なCLコマンドを書かせた手法を紹介しようと思います。これは、知っておくと便利な手法です。

私の課題は、ライブラリー内の数百の物理データ ファイルをすべて保管ファイルにコピーして、それらのファイルを別のIBM iシステム上へロードできるようにするということでした。ライブラリー保管(SAVLIB)コマンドは問題外でした。SAVLIBでは、非ファイル オブジェクト、論理ファイル、およびデバイス ファイルも保存されてしまいます。これでは、保管ファイルのサイズも非常に大きくなってしまいます。一方、オブジェクト保管(SAVOBJ)コマンドは、私が必要とした通りのものでした。1つのコマンドで最大300個のオブジェクトを保存できるからです。しかし、何百もの物理ファイル名をキー入力するというのは、「楽しくない」のは言うまでもなく、手指も疲れそうであり、正確性も欠きそうであり、理不尽です。幸い、私の代わりにSQLにその作業をやらせることが簡単にできました。以下に、その方法を紹介します。

魔法は、 begin という単語で始まり、 endという単語で終わります。その間には、SQL照会と、結果セットを処理するループがあります。以下のようになります。

begin
   declare v_Cmd     varchar(2048);
   declare v_Schema  varchar(  10)   default 'MYLIB';
   
   call qcmdexc('clrsavf mylib/mysavf');
   
   set v_Cmd = 'SAVOBJ OBJ(';
   
   for One_file as
      select t.Table_Name
        from systables as t
       where table_schema = 'MYLIB'
         and table_type = 'P'
         and file_type = 'D'
         and substr(table_name, 1, 3) <>  'SUM'
       order by table_name
   do
      set v_Cmd = v_Cmd concat ' ' concat One_file.Table_Name;
   end for;
   
   set v_Cmd = v_Cmd concat ') LIB(' concat v_Schema concat
               ') DEV(*SAVF) OBJTYPE(*FILE) SAVF(mylib/mysavf) TGTRLS(V7R3M0) SAVACT(*LIB)';
   call systools.lprintf('v_Cmd=/' concat v_Cmd concat '/');               
   call qcmdexc (v_Cmd);
end

これは、動的複合ステートメントとして知られているものです。この強力なツールについては、 この威厳ある刊行物 でも数年前にMike Sansoterraが紹介しています。私は、Access Client Solutions(ACS)の「SQLスクリプトの実行」ツール内で動的複合ステートメントを実行しました。

動的複合ステートメントは、名前のないプログラムと考えるとよいでしょう。さっそくですが、プログラムの例に漏れず、動的複合ステートメントは変数を持つことができます。

declare v_Cmd     varchar(2048);
declare v_Schema  varchar(  10)   default 'MYLIB';

より経験豊富なSQL PLの専門家のアドバイスに従って、変数名の先頭をv_にします。ただし、これは必須ではありません。

FORループを見てみましょう。

for One_file as
   select t.Table_Name
     from systables as t
    where table_schema = 'MYLIB'
      and table_type = 'P'
      and file_type = 'D'
      and substr(table_name, 1, 3) <>  'SUM'
    order by table_name
do
   set v_Cmd = v_Cmd concat ' ' concat One_file.Table_Name;
end for;

FORループは、カーソルの短縮形です。SETコマンドは、結果セットの各行ごとに実行し、保管ファイルに保存されるファイルのリストを構築します。

ここではQCMDEXCを2回呼び出しています。1回目は、保管ファイルを消去するため、2回目は、SAVOBJコマンドを実行するためです。

call qcmdexc('clrsavf mylib/mysavf');

set v_Cmd = 'SAVOBJ OBJ(';
set v_Cmd = v_Cmd concat ' ' concat One_file.Table_Name;
set v_Cmd = v_Cmd concat ') LIB(' concat v_Schema concat
  ') DEV(*SAVF) OBJTYPE(*FILE) SAVF(mylib/mysavf) TGTRLS(V7R3M0) SAVACT(*LIB)';
call qcmdexc (v_Cmd);

また、v_Cmdの値をジョブ ログへ書き込むために、LPRINTFの呼び出しも組み込みました。デバッグするオブジェクトがないため、これはスクリプトをデバッグするための1つの方法です。

call systools.lprintf('v_Cmd=/' concat v_Cmd concat '/');               

ACSには、ジョブ ログを表示する簡単な方法があります。

フォルダ

コマンドは、以下のようになりました。

SAVOBJ OBJ( ACCOUNT CUSTOMER DEPT . . . YTDSLS) 
       LIB(MYLIB) 
       DEV(*SAVF) 
       OBJTYPE(*FILE) 
       SAVF(mylib/mysavf) 
       TGTRLS(V7R3M0) 
       SAVACT(*LIB

これで出来上がりです。

少し考えてみてください。Scott Forstie氏と彼のチームのおかげで、素晴らしい IBM iサービス および Db2 for iサービス を利用できるようになっています。素晴らしいこれらのサービスは、オペレーティング システムに定義されている値を簡単に照会できるようにしてくれます。しかし、その値を 変更 することはできません。何を言おうとしているのかお分かりでしょうか。そうした素晴らしいサービスの1つを使用してデータにアクセスし、動的複合ステートメントを使用して、適切なCLコマンドを構築すれば、そうしたデータを変更することができます。1回限りのタスクでは、これ以上のものはありません。

そうした1回限りのタスクを定期的に実行することが必要になった場合には、動的複合ステートメントを永続オブジェクトに変更するのは簡単です。 begin の前に、CREATE PROCEDURE、適切なパラメーター リスト、およびその他の必要な節を追加するだけで、デバッグされたストアード プロシージャーを手にすることができます。

create or replace procedure mylib.myproc
   (in p_Schema char(10), in p_Savf char(10), in p_SavLib char(10))
begin

   declare v_Cmd     varchar(2048);

   call qcmdexc('clrsavf ' concat rtrim(p_SavLib) concat
                '/' concat ltrim(p_Savf));
   
   set v_Cmd = 'SAVOBJ OBJ(';
   
   for One_file as
      select t.Table_Name
        from systables as t
       where table_schema = p_Schema
         and table_type = 'P'
         and file_type = 'D'
         and substr(table_name, 1, 3) <>  'SUM'
       order by table_name
   do
      set v_Cmd = v_Cmd concat ' ' concat One_file.Table_Name;
   end for;
   
   set v_Cmd = v_Cmd concat ') LIB(' concat p_Schema concat
               ') DEV(*SAVF) OBJTYPE(*FILE) SAVF(' concat 
               rtrim(p_SavLib) concat
                '/' concat ltrim(p_Savf) concat
                ') TGTRLS(V7R3M0) SAVACT(*LIB)';
   call qcmdexc (v_Cmd);
   
end;

動的複合ステートメントは、私にとって骨の折れる作業を簡単な仕事にしてくれました。私がトラック運転手に転職するのは、まだ先のことになりそうです。

あわせて読みたい記事

PAGE TOP