DB2 for i の埋め込みSQL って実はけっこうカンタン!?

選択/除外の論理ファイルを置き換えてシステム資源を有効に使おう!」で OPNQRYF による SELECT/OMIT の論理ファイルの書き換えを紹介しましたが、 埋め込み SQL を使うともっと自由度の高い書き換えが可能です。

埋め込み SQL って難しい、って思ったりしていませんか??

RPG をちゃんと書けるんだったら全然難しいことはないんです。

実はかなり機械的に変換が可能です。(今回は V5R4 のシステムでの実行例です)

まずは F 仕様書を DECLARE CURSOR に変えてやればいいだけです。

 FTOKMSP    IF   E           K DISK 

        exec sql  DECLARE C1 CURSOR FOR      
                  SELECT
                    tkbang, tknakj, tkadr1, tkadr2,
                    tktiku, tkpost, tkuzan, tkgend        
                  FROM     Tokmsp        
                  ORDER BY tkbang ;  
       exec sql  OPEN C1 ;                  

に変えるだけです。
カンタンでしょ??


F 仕様書には物理ファイル名もしくは論理ファイル名を指定しますが、カーソルとしては SQL を定義するわけです。

実行可能な SQL なら何でもいいので、検索条件の自由度は論理ファイルとは比較にならないくらい自由です。
ORDER BY でも GROUP BY でも JOIN でもいろいろ可能です。

プログラム内の処理に先立って何か読み込みデータの加工をしておきたい時に(プログラムを汎用的にしたいような場合、けっこうありますよね)、
事前に論理ファイルを作っておく必要もありませんし、論理ファイルよりもいろんなことが可能です。

SQL の場合、SELECT 句に読む必要があるカラムだけを指定できるので余計なカラムを読んでくることもありません。
読み込みに必要なバッファなどを小さくできるので実はパフォーマンスにはいいんです。

ファイルのオープンは OPEN xxxx でカーソルのオープンを行います。タイミングは自由です。
RPG でも USROPN がありますので、そのへんは同じですね。


あとは実行したいデータベース処理に応じて書き替え方は異なってきます。

カーソルの各レコード(行)については FETCH xxxx で読み込んで処理を行います。
read で読んでいるのであれば、FETCH でもう読んできたことになります。それだけで書き換えの主な部分は完了ですね。
論理ファイルのお話をした時にちょっとふれましたが、RPG の READ/WRITE/UPDAT/DELET も "時代の産物" です。RPG でできたデータベース処理はすべて SQL でも可能で、SQL はそれ以上できる、と考えていいでしょう)


ループ制御も、RPG では標識や %eof 組み込み関数などを使用していると思いますが、
たいていはまったくそのままの形を保ったまま SQLSTATE を用いた判断に変えるだけで OK です。

たとえば、↓  は

        DoU (%EOF) ;             
           read      TOKMSP  ;   
           If (%EOF) ;           
              leave ;            
           else ;                
              exsr SR_TOKMS ;    
           endIf ;               
       endDo ;                  

こうなります。

        DoU (%subst(SQLSTATE:1:2) <> '00') ;              
           exec sql  FETCH C1 INTO      
                      :TKBANG, :TKNAKJ, :TKADR1, :TKADR2, 
                      :TKTIKU, :TKPOST, :TKUZAN, :TKGEND        
           if %subst(SQLSTATE:1:2) = '02' ;            
              leave ;            
           else ;                
              exsr SR_TOKMS ;    
           endIf ;               
       endDo ;                  

SQLSTATE の上二桁は「クラス・コード」となっており、このレベルでループの制御はできますね。
問題判別時には SQLSTATE 値(五桁)を参照すればより詳しい原因がわかります。

ほとんど同じようにコーディングできることに注目! です。

 

では、それぞれの全文を見てみましょう。また例によって EOL の例題を ILE RPG に書き換えたものです。

     H DATFMT(*JIS) DATEDIT(*YMD)                                                                   
      * BCH010 得意先マスターリストの印刷                                                                         
     FTOKMSP    IF   E           K DISK    RENAME(TOKMSP:TOKMSR)                                    
    FQPRINT    O    F  132        PRINTER OFLIND(*inOF)                                            
    D RECSU           S              5  0                                                          
      /free                                                                                         
        //見出し印刷                                                                                     
               except    MIDASI ;                                                                   
        //得意先マスターの読み込み                                                                              
               DoU (%EOF) ;                                                                         
                  read      TOKMSP  ;                                                               
                  If (%EOF) ;                                                                       
                     leave ;                                                                        
                  else ;                                                                            
                     exsr SR_TOKMS ;                                                                
                  endIf ;                                                                           
             endDo ;                                                                              
        //終了処理                                                                                      
               except    SAISHU  ;                                                                  
             *inLR = *on ;                                                                        
             return ;                                                                             
                                                                                                    
        BegSR SR_TOKMS ;                                                                            
       //ページ替えの確認                                                                                   
               If (*inOF) ;                                                                      
                     except    MIDASI ;                                                             
                     reset *inOF ;                                                                  
             endIf ;                                                                           
       //明細の印刷                                                                                      
                  except    MEISAI ;                                                                
                  RECSU +=  1  ;                                                                    
        EndSR ;                                                                                     
      /end-free                                                                                     
     OQPRINT    E            MIDASI           02                                                    
     O                                           51 ' **** 得意先マスター'                                 
     O                                           65 'リスト **** '                                     
     O                                           97 '作成日'                                           
     O                       UDATE         Y    105                                                 
     O                       PAGE          Z    113                                                 
     O                                          117 '頁'                                             
     O          E            MIDASI           03                                                    
     O                                            8 '得意先'                                           
     O                                           90 '地 区 郵 便'                                       
     O          E            MIDASI           04 06                                                 
     O                                           24 '番 号 得 意 先 名'                        
     O                                           50 '住  所  (1)   '                                  
     O                                           72 '住  所  (2)   '                                  
     O                                           90 'コード 番 号'                                       
     O                                          103 '売掛金残高'                                         
     O                                          117 '信用限度額'                                         
     O          E            MEISAI         2                                                       
     O                       TKBANG               6                                                 
     O                       TKNAKJ              29                                                 
     O                       TKADR1              51                                                 
     O                       TKADR2              73                                                 
     O                       TKTIKU              79                                                 
     O                       TKPOST              89                                                 
     O                       TKUZAN        J    103                                                 
     O                       TKGEND        J    117                                                 
     O          E            SAISHU         0                                                       
     O                                           18 ' *レコード件数* '                              
     O                       RECSU         1     25            

 

こちらが埋め込みSQL を使用して書きかえたものです。ソースタイプは SQLRPGLE にする必要があります。(でないと構文チェックのエラーがたくさん出て大変なことになります)
該当する元の行は比較対照のために残しておきました。


     H DATFMT(*JIS) DATEDIT(*YMD)
      * BCH010得意先マスターリストの印刷
     FQPRINT    O    F  132        PRINTER OFLIND(*inOF)
     F*TOKMSP   IF   E           K DISK    RENAME(TOKMSP:TOKMSR)
      *↑この F仕様書の定義が不要
     D RECSU           S              5  0
      *↓ファイルのフィールドをワークの変数として使うため定義
     D TOKDS         E DS                  EXTNAME(TOKMSP)
      /free                                            
               exec sql  DECLARE C1 CURSOR FOR      
                         SELECT tkbang,                     
                                tknakj,                     
                                tkadr1,                 
                                tkadr2,                  
                                tktiku,                 
                                tkpost,            
                                tkuzan,                        
                                tkgend                      
                           FROM Tokmsp                
                           ORDER BY tkbang ;       
                                                       
               exec sql  OPEN C1 ;                   
                                                  
        //見出し印刷                       
               except    MIDASI ;
        //得意先マスターの読み込み     
         //     DoU (%EOF) ;             
               DoU (%subst(SQLSTATE:1:2) <> '00') ;    
        //        read      TOKMSP  ;              
                  exec sql  FETCH C1 INTO          
                                 :TKBANG,      
                                 :TKNAKJ,          
                                 :TKADR1, 
                                 :TKADR2,    
                                 :TKTIKU,   
                                 :TKPOST,          
                                 :TKUZAN,  
                                 :TKGEND ;    
        //         If (%EOF) ;               
                   if %subst(SQLSTATE:1:2) = '02' ; 
                      leave ;               
                   else ;                    
                      exsr SR_TOKMS ;     
                   endIf ;       
               EndDo ;         
        //終了処理                      
               except  SAISHU  ;           
                                   
             exec sql  CLOSE C1 ;    
             *inLR = *on ;           
             Return ;         
                                       
        BegSR SR_TOKMS ;   
       //ページ替えの確認        
                   If (*inOF) ;      
                   except    MIDASI ;    
                   reset  *inOF ;         
                endIf ;            
       //明細の印刷                       
                   except   MEISAI ;      
                RECSU +=  1  ;        
        EndSR ;                
      /end-free         
     OQPRINT    E            MIDASI           02     
     O                                           51 ' **** 得意先マスター'  
     O                                           65 'リスト **** '           
     O                                           97 '作成日'              
     O                       UDATE         Y    105         
     O                       PAGE          Z    113      
     O                                          117 '頁'        
     O          E            MIDASI           03                
     O                                            8 '得意先'          
     O                                           90 '地 区 郵 便'   
     O          E            MIDASI           04 06                        
     O                                           24 '番 号 得 意 先 名'  
     O                                           50 '住  所  (1)   '   
     O                                           72 '住  所  (2)   '   
     O                                           90 'コード 番 号'
     O                                          103 '売掛金残高'        
     O                                          117 '信用限度額'
     O          E            MEISAI         2
     O                       TKBANG               6
     O                       TKNAKJ              29
     O                       TKADR1              51
     O                       TKADR2              73
     O                       TKTIKU              79
     O                       TKPOST              89
     O                       TKUZAN        J    103
     O                       TKGEND        J    117
     O          E            SAISHU         0
     O                                           18 ' *レコード件数* '
     O                       RECSU         1     25                                                 

 

コンパイルのコマンドは CRTBNDRPG から CRTSQLRPGI に変わります。

サイズはちょっと増えます(144KB → 228KB )が、パフォーマンスは実はそんなに変わりません。
↓ がそれぞれを 3回ほど別のジョブで実行してみて、PEX のプロファイルで取った "Total DB CPU (μs)" の値です。

  1回目 2回目 3回目
RPG 33,872 19,920 29,448
SQLRPG 33,608 16,472 24,216

レスポンスタイム、CPU 使用率の観点から言って、あんまり差がないことがわかると思います。
(CPU 使用時間ですから、そのまま CPU の使用率にも直結しますね)

 

くりかえしになりますが、SQL をそのまま使えるので自由度があがりますし、JDBC で Java のプログラムを書いたり、ADO で VB を書いたりする時にスキルの共有になります。
また、STRSQL 画面などからテストしてみてすぐに結果が確認できる、という利点もあります。

けっこうカンタンにできる埋め込みSQL、活用しない手はないと思いますよ!!

iForum: DB2 for i の埋め込みSQL って実はけっこうカンタン!?
http://www.iforum.ne.jp/article.php/20100115201349336