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)