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)