HTTPサーバーとWeb開発

71. あいまい検索

Google や Yahoo のような検索エンジンは毎日のように身近に使用されている。
コード検索ではなく、名前の一部だけで検索する「あいまい検索」を
取り入れれば、いかにも Web業務として見えるようになりユーザー操作も
一段と扱いやすいものとなる。
これと同じ機能を実現するには SQL の WildCard を使えばよいのだろうと
Query/400 に慣れている System i のユーザーは考えるだろう。
しかし実際にやってみるとコンパイル・エラーに悩まされたり、
思うように検索結果を抽出できないという障壁にすぐに出くわしてしまう。
IBM マニュアルを調べて見てもあいまい検索の方法に関する記述や解説はない。
実はホンの少しのコツを知るだけであいまい検索も簡単に実現することができる。

例として次の初期画面をご覧頂きたい。

あいまい検索初期画面

これは商品名の一部に「テスト」という文字列が含まれるものを抽出する例である。
「テスト」と文字列を入力して「検索」ボタンを押すと次のように
検索結果が表示される。

あいまい検索結果画面

【 解説 】

ILE-RPG ソースの中に SQL文を埋め込む SQLパッケージ ( SQLPKG ) として
RPG ソースを作成して SQL 文として

  SELECT T1.SHCODE, T1.SHNAME, T1.SHTANK, T1.SHSCOD, T1.SHSCOD
         FROM QTRFIL/SHOHIN T1                              
       WHERE T1.SHNAME LIKE :SEARCH          
       ORDER BY T1.SHCODE                                   

として SQL 文を作成して実行するのだが、
あいまい検索として

       WHERE T1.SHNAME LIKE :SEARCH 

が検索を指示している部分であるが 変数 SEARCH は 商品名 SHNAME と同じ長さ、
属性として

   *LIKE         DEFINE    SHNAME        SEARCH

として定義しておく。
ここでSQL に詳しい人であれば LIKE 句を

   LIKE SUBSTR(:SEARCH, 1, :LEN)

のようにしたいところだが、それでは検索できない文字列が発生してしまう。
そこで LIKE 句は

   LIKE :SEARCH

とするわけだが ワイルド・カードの通常の使用方法であれば、

   :SEARCH = '%' + (検索文字列) + '%'

のように検索文字列の両端を文字 '%' で囲むことになるが、それでは不足となってしまう。
正解は

   :SEARCH = '% + (検索文字列) + '%' + .... '%'

のようにして変数 SERACH の残りの部分もすべて、文字 '%' によって埋め尽くさなければならない。
これがあいまい検索のテクニックとなるのである。
そこで実際の RPG ソースは次のようになる。
SEU でのソース仕様タイプは SQLRPGLE にしておくこと。

---------------------------------------------------------------------------------
0001.00 H DATEDIT(*YMD/) COPYRIGHT('(C) OfficeQuattro Co,.Ltd Japan 2008-')      
0002.00 F**********  商品マスターファイル         *****************************  
0003.00 F*    レポート照会                                                       
0004.00 F**********************************************************************  
0005.00 F**********************************************************************  
0006.00  /COPY ASNET.USR/QRPGLESRC,PROTOTYPE5                                    
0007.00 D RTVERR          C                   CONST(' レコード検索エラー ')      
0008.00 D NOTFOUND        C                   CONST(' レコードが見つからない。 ')
0009.00 D MAXGYO          S              4  0 INZ(15)                            
0010.00 D LEN             S             10I 0                                    
0011.00 D AR              S              1    DIM(24)                            
0012.00 D*( データ・ベース外部データ構造 )                                       
0013.00 D FMT001        E DS                  EXTNAME(SHOHIN)                    
0014.00 C******************************************************                  
0015.00 C*               メイン・ルーチン                                        
0016.00 C******************************************************                  
0017.00 C                   EXSR      STDIN                                      
0018.00 C******************************************************                  
0019.00 C*    SQL 文のカーソルの前準備                                           
0020.00 C******************************************************                  
0021.00 C* SELECT 文によってカーソル C1 を用意                                   
0022.00 C/EXEC SQL DECLARE C1 CURSOR FOR                                         
0023.00 C+  SELECT T1.SHCODE, T1.SHNAME, T1.SHTANK, T1.SHSCOD, T1.SHSCOD         
024.00 C+           FROM QTRFIL/SHOHIN T1                                       
025.00 C+         WHERE T1.SHNAME LIKE :SEARCH                                  
026.00 C+         ORDER BY T1.SHCODE                                            
027.00 C/END-EXEC                                                               
028.00 C*  カーソルをオープン                                                   
029.00 C/EXEC SQL                                                               
030.00 C+   OPEN C1                                                             
031.00 C/END-EXEC                                                               
032.00 C                   MOVEL(P)  SCHVALUE      VALUE                        
033.00 C                   CALLP     SETFLD('$(SEARCH)': VALUE)                 
034.00 C                   SETOFF                                       80      
035.00 C/EXEC SQL WHENEVER NOT FOUND GOTO EOF                                   
036.00 C/END-EXEC                                                               
037.00 C     1             DO        MAXGYO        RECORD            4 0        
038.00 C/EXEC SQL                                                               
039.00 C+   FETCH C1 INTO :SHCODE, :SHNAME, :SHTANK, :SHSCOD, :SHSCOD           
040.00 C/END-EXEC                                                               
041.00 C                   SETON                                        80      
042.00 C                   EXSR      CHECK                                      
043.00 C*( REPORT 文への埋め込み )                                              
044.00 C                   EXSR      REPADD                                     
045.00 C                   END                                                  
046.00 C     EOF           TAG                                                  
047.00 C*  カーソルをクローズ                                                   
0048.00 C/EXEC SQL                                                             
0049.00 C+  CLOSE C1                                                           
0050.00 C/END-EXEC                                                             
0051.00 C*( HTML  の出力 *IN80--READ 成功 )                                    
0052.00 C     *IN80         IFEQ      *ON                                      
0053.00 C                   CALLP     WRITE                                    
0054.00 C                   ELSE                                               
0055.00 C                   MOVEL     RTVERR        MSGTXT#                    
0056.00 C                   MOVEL     NOTFOUND      MSG#                       
0057.00 C                   EXSR      ERRMSG                                   
0058.00 C                   END                                                
0059.00 C     END           TAG                                                
0060.00 C                   SETON                                        LR    
0061.00 C                   RETURN                                             
0062.00 C******************************************************                
0063.00 C     STDIN         BEGSR                                              
0064.00 C******************************************************                
0065.00 C*( HTML からの標準入力されたフィールド値の受け取り )                  
0066.00 C                   EVAL      TEMPLATE = CGIPARM('@TEMPLATE ')         
0067.00 C                   MOVEL     TEMPLATE      FLD7              7        
0068.00 C     FLD7          CABEQ     '*ERROR*'     END                        
0069.00 C*( HTML からフィールド値の取得 )                                      
0070.00 C                   MOVE      *BLANKS       VALUE                      
0071.00 C                   EVAL      VALUE  = CGIPARM('SHNAME    ')           
0072.00 C                   MOVEL(P)  VALUE         SCHVALUE                  
0073.00 C                   MOVEA     VALUE         AR(2)                     
0074.00 C     *LIKE         DEFINE    SHNAME        SEARCH                    
0075.00 C     1             DO        24            N                 4 0     
0076.00 C     AR(N)         IFEQ      ' '                                     
0077.00 C                   MOVE      '%'           AR(N)                     
0078.00 C                   END                                               
0079.00 C                   END                                               
0080.00 C                   MOVEA     AR            SEARCH                    
0081.00 C     *LIKE         DEFINE    SHNAME        SCHVALUE                  
0082.00 C*( テンプレートを宣言 )                                              
0083.00 C                   EVAL      RESULT = OPENHTML(TEMPLATE)             
0084.00 C     RESULT        CABEQ     FALSE         END                       
0085.00 C                   ENDSR                                             
0086.00 C******************************************************               
0087.00 C     CHECK         BEGSR                                             
0088.00 C******************************************************               
0089.00 C                   ENDSR                                             
0090.00 C******************************************************               
0091.00 C     REPADD        BEGSR                                             
0092.00 C******************************************************               
0093.00 C*( REPORT 文へ値を追加 )                                             
0094.00 C                   MOVEL(P)  SHCODE        VALUE                     
0095.00 C                   CALLP     SETFLD('SHCODE    ': VALUE)             
0096.00 C                   CALLP     SETFLD('$(KEY)    ': VALUE)               
0097.00 C                   MOVEL(P)  SHNAME        VALUE                       
0098.00 C                   CALLP     SETFLD('SHNAME    ': VALUE)               
0099.00 C                   MOVEL(P)  SHTANK        VALUE                       
0100.00 C                   CALLP     SETFLD2('SHTANK':VALUE:0007:0:0010:'J')   
0101.00 C                   MOVEL(P)  SHSCOD        VALUE                       
0102.00 C                   CALLP     SETFLD('SHSCOD    ': VALUE)               
0103.00 C     WRTEND        ENDSR                                               
0104.00 C******************************************************                 
0105.00 C     ERRMSG        BEGSR                                               
0106.00 C******************************************************                 
0107.00 C                   MOVE      'CPF9898'     MSGID#                      
0108.00 C                   MOVE      'QCPFMSG   '  MSGF#                       
0109.00 C                   MOVE      'QSYS      '  MSGLIB#                     
0110.00 C                   CALLP     SNDERRMSG('RPGCGI': 'SQLCI' : MSGID# :    
0111.00 C                             MSGF# : MSGLIB# : MSGTXT# : MSG#)         
0112.00 C                   ENDSR                                               
---------------------------------------------------------------------------------
【 コンパイル 】
  CRTSQLRPGI QTEMP/MAR004 SRCFILE(MYSRCLIB/QRPGLESRC) OBJTYPE(*MODULE)
  CRTPGM CGIBIN/MAR004 MODULE(QTEMP/MAR004) BNDSRVPGM(ASNET.COM/RPGENGNE5) ACTGRP(*NEW) AUT(*ALL)