はじめに
多くの人が、OPNQRYFに興味を持っていて、または、使っているか、使おうとしているか、ということが分かりました。そこで、再び、OPNQRYFを取り上げます。ここでは、データの選択、並び替えについて、説明したいと思います。
なぜ、使うのか
私の場合、RPGサイクルによる制御(レベル)標識をよく使います。勿論、全手順で、比較しながらデータの合計処理をしても良いのですが、開発にやや時間がかかります。それで、サイクルを多用して、開発とテストの工程を縮めようとしているわけです。ところが、そのRPGサイクルでは、オープンしたファイルメンバーを、最初から最後まで、全て処理してしまいます。もし200万件あって、実際必要なのが、その中の10万件としても、RPGサイクルのプログラムは、200万件を処理してしまいます。この場合、プログラム内部で、パラメータとして受け取った値と、ファイルの中の或フィールドの値を比較して、該当するものは、処理へ進み、そうでないものは、スキップして次のレコードへ、という感じになります。勿論、結果は正しいのですが、全手順で、SETLLでREADした方が、OSのDBMSが最初からキーをメンテしてくれていて、それをキーとして扱えるわけで、全体処理のRPGサイクルに比べたら、ずっと、処理時間が少なくてすみます。開発の容易さと、実行効率の良さ、のどちらを取ればいいのか、という感じになります。
しかしながら、このOPNQRYFは、RPGがファイルメンバーをオープンする前に、SQLのように、データを選択、並び替えなど、してくれて、その結果のデータを、RPGに引き継がせることが可能です。つまり、先ほどの例だと、200万件が、選択されて、10万件となって(これはシステム内部のこと)、RPGは、200万件ではなくて、10万件を処理するだけとなります。処理時間は、やはり、SETLL+READにはかないませんが、それでも、それを上回るメリットを持っています。
プログラムの処理系統 |
大量データ実行効率
(データ選択を含む場合) |
開発の容易さ |
仕様変更の修正の容易さ |
RPGサイクル |
× |
○ |
○ |
全手順(SETLL+READ系) |
○ 論理ファイルが既に有る場合 |
△ 場合によっては、× |
△ 場合によっては、× |
OPNQRYF+RPGサイクル |
△ |
○ |
○ |
こんな訳で、よくOPNQRYF+RPGサイクルを使います。それから、ほとんどが、バッチ系のプログラムのお話です。たまに、OPNQRYF+対話型も作ります。
OPNQRYFの基本
PGM
OVRDBF AAAA SHARE(*YES) OPNQRYF AAAA QRYSLT('YEAR=1998 & FLAG="W"') KEYFLD(KEY1) CALL RPGPGM CLOF AAAA DLTOVR AAA
RETURN ENDPGM
QRYSLTについて
ここでは、指定したファイルのデータを選択する、指示文を記入します。たくさんの関数が準備されています。中には、GRPSLTにしか使えないものが、ありますので注意して下さい。
最もよく使うのは、
%RANGE(下限値 上限値)
%RANGEは、フィールドまたは式の下限値および上限値を指定するために使用します。
%VALUES(許容値...)
%VALUESは、フィールドまたは式の許容値のリストを指定するために使用します。
%WLDCRD (''パターン・ストリング'' ''ワイルド文字'')
%WLDCRDは、比較演算子の左端に指定されていなければならない文字または16進数フィールドまたはストリング式(単一文字ストリング・リテラルからなる式を除く)の、ワイルドカード走査を実行するために使用されるパターンを指定します。
%SST(ストリング引数 開始位置の式<長さ式>)
%SSTと%SUBSTRINGは引数として文字、16進数、DBCS、あるいはグラフィック・ストリング、開始位置の式、および任意指定の長さ式を受け入れます。
QRYSLTの例
ここでは、理屈よりも、たくさんのCLPでの例を見て貰って、OPNQRYFを理解して貰おうと、考えています。
例1)通常の指定の例。F8YYMMは数字フィールドで、F8STF#が文字フィールドで有ることがおわかりですか?そう、ダブルコーテーションの有無で判断できるんですよね。
PGM (&PIOMIT &PIYMS &PIYME &PIOUTCS &PIOUTCE)
DCL &PIOMIT *CHAR 1
DCL &PIYMS *CHAR 4
DCL &PIYME *CHAR 4
DCL &PIOUTCS *CHAR 3
DCL &PIOUTCE *CHAR 3
OVRDBF HTW220L5 SHARE(*YES)
OPNQRYF HTW220L5 +
QRYSLT('F8YYMM=%RANGE('|<&PIYMS |> &PIYME |<') & +
F8OUTC=%RANGE('|<&PIOUTCS|> &PIOUTCE|<') & +
F8STF# *NE "000000"') +
KEYFLD(*FILE)
OVRDBF DWNDTA20 DWNDTA/DWNDTA20
CLRPFM DWNDTA/DWNDTA20
CALL DWW020 (&PIOMIT &PIYMS)
CLOF HTW220L5
DLTOVR *ALL
RETURN
ENDPGM |
例2) ここでは、QRYSLTの内容を、わざと別のフィールド&QRYSLTに指定しています。&QRYSLTは5000バイト以内(v3)まで指定できます。この変数を、使い回すことで、ロジックの簡略化を狙っています。
PGM (&PICST &PIYEAR &PIMONT)
/*宣言*/
DCL &PICST *CHAR 4
DCL &PIYEAR *CHAR 4
DCL &PIMONT *CHAR 2
DCL &JOB *CHAR 10
DCL &QRYSLT *CHAR 1024
MONMSG CPF0000 *N GOTO ERR
RTVJOBA JOB(&JOB)
/* OPENQRYF 実行 */
CHGVAR &QRYSLT ('CSTNO='|<&PICST|<' & +
DLVDT=%RANGE('|<&PIYEAR|<&PIMONT|<'00' |> &PIYEAR|<&PIMONT|<'99)')
OVRDBF ODRINFL1 SHARE(*YES)
OPNQRYF FILE(ODRINFL1) QRYSLT(&QRYSLT) KEYFLD(*FILE)
OVRDBF NCRINFL1 SHARE(*YES)
OPNQRYF FILE(NCRINFL1) QRYSLT(&QRYSLT) KEYFLD(*FILE)
OVRPRTF QPRT132 SPLFNAME(&JOB)
CALL DSP050 (&PICST &PIYEAR &PIMONT)
DLTOVR QPRT132
ERR:
/* OPENQRYF 後処理 */
CLOF ODRINFL1
MONMSG CPF0000
DLTOVR ODRINFL1
CLOF NCRINFL1
MONMSG CPF0000
DLTOVR NCRINFL1
RETURN
ENDPGM |
例3)ここでは、画面から指定された、値を、「除外」しようとしています。&PIOMITに3*10個の除外データが入ります。10個はあくまで最大値であって、すべて入力されているとは限りません。QRYSLTを変数で指定しなくては出来ない方法です。また、&PBACPTでは、処理の順番を指定しているので、この値を元に、KEYFLDの内容を変更しています。
PGM (&PBFUID &PBACPT &PBPSTE &PBSKIP &PICSTS &PICSTE &PIOMT)
/* |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| */
/* | DECLARE VARIABLES AND A FILE | */
/* |_______________________________________________________________| */
DCL &PBFUID *CHAR 8
DCL &PBSKIP *CHAR 1
DCL &PBACPT *CHAR 1
DCL &PBPSTE *CHAR 1
DCL &PICSTS *CHAR 3
DCL &PICSTE *CHAR 3
DCL &PIOMT *CHAR 30
DCL &W1O01 *CHAR 3
DCL &W1O02 *CHAR 3
DCL &W1O03 *CHAR 3
DCL &W1O04 *CHAR 3
DCL &W1O05 *CHAR 3
DCL &W1O06 *CHAR 3
DCL &W1O07 *CHAR 3
DCL &W1O08 *CHAR 3
DCL &W1O09 *CHAR 3
DCL &W1O10 *CHAR 3
DCL &QRYSLT *CHAR 1000
MONMSG CPF0000
CHGVAR &W1O01 %SST(&PIOMT 1 3)
CHGVAR &W1O02 %SST(&PIOMT 4 3)
CHGVAR &W1O03 %SST(&PIOMT 7 3)
CHGVAR &W1O04 %SST(&PIOMT 10 3)
CHGVAR &W1O05 %SST(&PIOMT 13 3)
CHGVAR &W1O06 %SST(&PIOMT 16 3)
CHGVAR &W1O07 %SST(&PIOMT 19 3)
CHGVAR &W1O08 %SST(&PIOMT 22 3)
CHGVAR &W1O09 %SST(&PIOMT 25 3)
CHGVAR &W1O10 %SST(&PIOMT 28 3)
...略 ...
/*--------------------------*/
/* DM印刷 */
/*--------------------------*/
CHGVAR &QRYSLT ('MDOUTC=%RANGE('|<&PICSTS|>&PICSTE|<')')
IF (&PIOMT *NE ' ') DO
IF (&W1O01 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O01)
IF (&W1O02 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O02)
IF (&W1O03 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O03)
IF (&W1O04 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O04)
IF (&W1O05 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O05)
IF (&W1O06 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O06)
IF (&W1O07 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O07)
IF (&W1O08 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O08)
IF (&W1O09 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O09)
IF (&W1O10 *NE ' ') CHGVAR &QRYSLT (&QRYSLT|< '& MDOUTC *NE'|> &W1O10)
ENDDO
OVRPRTF QPRT198 HOLD(*YES) SPLFNAME('NB'|<&PBFUID)
OVRPRTF MBDMPRT1 HOLD(*YES) SPLFNAME('DM'|<&PBFUID)
OVRPRTF MBDMPRT2 HOLD(*YES) SPLFNAME('DM'|<&PBFUID)
OVRDBF FUTGTMP MBR(&PBFUID) SHARE(*YES)
IF (&PBACPT='1') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD(*FILE)
ELSE IF (&PBACPT='2') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD((MDOUTC)(MDZIP))
ELSE IF (&PBACPT='3') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD((MDZIP)(MDOUTC))
CALL FUP110 (&PBFUID &PBPSTE &PBSKIP &PBACPT)
CLOF FUTGTMP
MONMSG CPF0000
DLTOVR *ALL
END:
RETURN
ENDPGM |
例4)これも、指定した内容で、&QRYSLTの内容を変更している例です。このように、アイデア次第でかなり柔軟な、選択文が作成できます。無駄に長いので、余計な部分は省略しました。
PGM (&PBFUID &POTGTC)
DCL &POTGTC *CHAR 7
DCL &PBFUID *CHAR 8
DCL &W1CURRS *DEC (10 0)
DCL &W1SLSC *CHAR 1
DCL &W1SCST *CHAR 3
DCL &W1ECST *CHAR 3
DCL &W1DLTD *CHAR 1
DCL &W1DLTX *CHAR 1
DCL &W1SYM *CHAR 6
DCL &W1EYM *CHAR 6
DCL &W2S_4 *CHAR 4
DCL &W2E_4 *CHAR 4
DCL &W2S_2 *CHAR 2
DCL &W2E_2 *CHAR 2
DCL &W1SBTY *CHAR 4
DCL &W1EBTY *CHAR 4
DCL &W1SBTM *CHAR 2
DCL &W1EBTM *CHAR 2
DCL &W1SOPN *CHAR 8
DCL &W1EOPN *CHAR 8
DCL &W1DMX *CHAR 1
DCL &W1TXT *CHAR 40
DCL &QRYSLT *CHAR 1024
/*-----------------------------------*/
/* 該当顧客判定と購入未購入検査 */
/*-----------------------------------*/
OVRDBF FUSCHWP QTEMP/FUSCHWP FRCRATIO(200) SEQONLY(*YES 200)
OVRDBF FUCNTMP MBR(&PBFUID)
/* MBMSTML5 OPEN QUERY FILE */
IF (&W1SCST *NE '000' | &W1ECST *NE '999') DO
CHGVAR &QRYSLT ('D0OUTC=%RANGE('|<&W1SCST|>&W1ECST|<')')
ENDDO
IF (&W1SYM *NE '000000' | &W1EYM *NE '999999') DO
IF (&QRYSLT *NE ' ') CHGVAR &QRYSLT (&QRYSLT |< '&')
CHGVAR &W2S_4 %SST(&W1SYM 3 4)
CHGVAR &W2E_4 %SST(&W1EYM 3 4)
CHGVAR &QRYSLT (&QRYSLT|<'D0YYMM=%RANGE('|<&W2S_4|>&W2E_4|<')')
ENDDO
IF (&W1DLTD='N') DO
IF (&QRYSLT *NE ' ') CHGVAR &QRYSLT (&QRYSLT |< '&')
CHGVAR &QRYSLT (&QRYSLT|<'D0DLT *NE "D"')
ENDDO
IF (&W1DLTX='N') DO
IF (&QRYSLT *NE ' ') CHGVAR &QRYSLT (&QRYSLT |< '&')
CHGVAR &QRYSLT (&QRYSLT|<'D0DLT *NE "X"')
ENDDO
IF (&W1DMX='Y') DO
IF (&QRYSLT *NE ' ') CHGVAR &QRYSLT (&QRYSLT |< '&')
CHGVAR &QRYSLT (&QRYSLT|<'D0DMX=" "')
ENDDO
IF (&QRYSLT *NE ' ') CHGVAR &QRYSLT (&QRYSLT |< '&')
CHGVAR &QRYSLT (&QRYSLT|<'D0DLT *NE "E"')
OVRDBF MBMSTML5 SHARE(*YES)
OPNQRYF MBMSTML5 QRYSLT(&QRYSLT) KEYFLD(*FILE)
OVRDBF ANACLIL6 SHARE(*YES)
OPNQRYF ANACLIL6 QRYSLT('C2FG81=%RANGE('|<&W1SOPN|>&W1EOPN|<')') +
KEYFLD(*FILE)
CALL FUU101 (&PBFUID)
CLOF ANACLIL6
MONMSG CPF0000
CLOF MBMSTML5
MONMSG CPF0000
DLTOVR *ALL
RTVMBRD QTEMP/FUSCHWP NBRCURRCD(&W1CURRS)
CHGVAR &POTGTC &W1CURRS
\END:
RETURN
ENDPGM |
例5)ここでは、QRYSLTに、%VALUESを使ってみました。%VALUESでは、データを羅列するような指定の仕方になります。
PGM (&W1STRU &W1ENDU &W1STRD &W1ENDD &W1STRT &W1ENDT &W1STRO &W1ENDO +
&W1STR# &W1END# &W1ADD &W1BFR &W1CHG &W1DLT &W1ERS &W1RAT)
/*宣言*/
DCL &W1STRU *CHAR 10
DCL &W1ENDU *CHAR 10
DCL &W1STRD *CHAR 6
DCL &W1ENDD *CHAR 6
DCL &W1STRT *CHAR 6
DCL &W1ENDT *CHAR 6
DCL &W1STRO *CHAR 3
DCL &W1ENDO *CHAR 3
DCL &W1STR# *CHAR 6
DCL &W1END# *CHAR 6
DCL &W1ADD *CHAR 1
DCL &W1BFR *CHAR 1
DCL &W1CHG *CHAR 1
DCL &W1DLT *CHAR 1
DCL &W1ERS *CHAR 1
DCL &W1RAT *CHAR 1
DCL &QRYSLT1 *CHAR 1024
DCL &QRYSLT2 *CHAR 200
MONMSG CPF0000 *N GOTO ERR
/* OPENQRYF 実行 */
CHGVAR &QRYSLT1 +
('D4USID=%RANGE("'|< &W1STRU |<'" "'|< &W1ENDU |<'") & +
D4OUTC=%RANGE(' |< &W1STRO |> &W1ENDO |<') & +
D4MBR#=%RANGE(' |< &W1STR# |> &W1END# |<') & +
D4QDAT=%RANGE(' |< &W1STRD |> &W1ENDD |<') & +
D4QTIM=%RANGE(' |< &W1STRT |> &W1ENDT |<' )')
CHGVAR &QRYSLT2 (' ')
IF (&W1ADD='Y'| &W1BFR='Y'|&W1CHG='Y'|&W1ERS='Y'|&W1DLT='Y') DO
CHGVAR &QRYSLT2 ('D4ACT=%VALUES(')
IF (&W1ADD='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"A"')
IF (&W1BFR='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"B"')
IF (&W1CHG='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"C"')
IF (&W1DLT='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"D"')
IF (&W1ERS='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"E"')
IF (&W1RAT='Y') CHGVAR &QRYSLT2 (&QRYSLT2 |>'"R"')
CHGVAR &QRYSLT2 (&QRYSLT2 |<')')
CHGVAR &QRYSLT1 (&QRYSLT1 |> '&' |> &QRYSLT2)
ENDDO
OVRDBF MBM010W SHARE(*YES)
OPNQRYF FILE((MBM010W)) QRYSLT(&QRYSLT1) KEYFLD(*NONE)
CALL MBP070 (&W1STRU &W1ENDU &W1STRD &W1ENDD &W1STRT &W1ENDT +
&W1STRO &W1ENDO &W1STR# &W1END#)
ERR:
/* OPENQRYF 後処理 */
CLOF MBM010W
MONMSG CPF0000
DLTOVR MBM010W
RETURN
ENDPGM |
例6)ここでは、MAPFLDの例です。数字フィールドG0SECを文字3桁にしてから、それを、G0ACTと文字合成して、それを、QRYSLTで利用しています。無駄に長いので、余計な部分は省略しました。
PGM (&CMP &YEAR &CNT)
...略 ...
OVRDBF GLACTMP SHARE(*YES)
OPNQRYF GLACTMP QRYSLT(' +
G0CFY='|<&YEAR|<'& G0CMP="'|<&CMP|<'" & G0DLT=" " +
& W1ACTE *NE "999999999" +
& W1ACTE *NE "'|<&PLACT|<'" +
& G0POST="P" & G0BSPL="P"') +
MAPFLD((W1SECE '%DIGITS(G0SEC)' *CHAR 3) +
(W1ACTE 'G0ACT *CAT W1SECE' *CHAR 9)) KEYFLD(*FILE)
CALL GLC030 (&CMP &YEAR &CNT)
CLOF GLACTMP
MONMSG CPF0000
DLTOVR *ALL
...略 ...
RETURN
ENDPGM |
式について
AS/400 CL(制御言語)解説書バージョン3 1.6.107 OPNQRYF (QUERYファイル・オープン)コマンドより
式
QRYSLT、GRPSLT、およびMAPFLDパラメーターに指定する式は、他のCLコマンドのパラメーターに指定する式によく似ています。フィールド値と定数との組合せを使って、論理演算、比較演算、およびストリング演算が行われます。記号演算子および名前演算子のほか多くの組込み関数が使用でき、また計算の順序を制御するために括弧を使用します。
OPNQRYFコマンドのパラメーターで指定する式と他のCLコマンドのパラメーターで指定する式との間には相違点もあります。次のリストは、QRYSLT、GRPSLT、およびMAPFLDパラメーターで使用する式と、CLの通常の式との相違点を要約したものです。
式ストリングの中にブランクまたは特殊文字を含める場合は、そのストリングをアポストロフィで囲まなければなりません。
数値リテラルおよびストリング・リテラルについては次のような相違点があります。
文字ストリング定数はアポストロフィまたは2重引用符で囲みます。数値定数の先行ゼロおよび後書きゼロはその属性の有効部分です。式の中で浮動小数点定数(特殊値*INFおよび*NEGINFを含む)が使用されます。
CL変数とデータベース・フィールドとの相違点は次のとおりです。
- データベース・フィールド名には接頭アンパーサンド(&)は使用しません。
- 修飾フィールド名が使用できます。
- データベース・フィールドについては「論理」フィールド・タイプはありません。
- データベース・フィールドについては多くの追加データ・タイプがサポートされています。
次のCL演算子は、OPNQRYFコマンドではサポートされていません。
CLサポートに加えて次の追加演算子が使用できます。
- // (余り)
- ** (累乗)
- *CT (文字走査の場合の「包含」)
- *XORまたは&& (排他的論理和)
組込み関数については次のような相違点があります。
- %SWITCH組込み関数は使用できません。
- 多くの追加の組込み関数が使用できます。
- 通常の場合は、組込み関数の引数として組込み関数および式をネストして使用できます(たとえば、'%LOG(%SIN(x))')。
- 組込み関数の引数として式を使用できるようにするために、符号付き数値または式を引数とする場合は括弧で囲まなければなりません(たとえば、'%MIN(3
(-2) x (y+4))')。
次の表は、QRYSLT、 GRPSLT、 またはMAPFLDパラメーターで式に使用するすべての演算子についてそれぞれの優先順位を示しています。MAPFLDパラメーターに指定する式の中で使用できるのは、優先順位1から5の演算子(*NOTおよび¬演算子を除く)だけです。
優先順位 |
演算子 |
1 |
+、 − (符号付き数値に使用される場合)、*NOT、¬
|
2 |
** |
3 |
*、 / 、// (/の前または後(もしくはその両方)にスペースが必要)
|
4 |
+、 - (2つのオペランドの間で使用されている場合) |
5 |
*CAT, || |
6 |
*GT, *LT, *EQ, *GE, *LE, *NE, *NG, *NL, *CT, >, <, =,
>=,<=,¬=, ¬>, ¬< |
7 |
*AND、 & |
8 |
*OR, *XOR, D, && |
|
KEYFLDについて
アクセスの順番の指定を、フィールドで指定する事も可能です。KEYFLD(&KEYFLD)といった感じです。しかしながら、複数キーを指定する場合、有る場合は1個、有る場合は2個となる様な場合、KEYFLD(&KEY1
&KEY2)では、エラーが起こることがあります。つまり、キーが一個の場合、&KEY2が無駄になるのです。この場合、QCMDEXCを使うことになります。OPNQRYF全体の文字列を、QCMDEXCに手渡すことになります。しかしこれでは、かなり面倒ですので、上記の例にも有るように、パラメータによって、OPNQRYF全体を使い分けた方が、楽でしょう。この場合、QRYSLTは変数化した方が指定文が減って、楽です。(QRYSLTの内容を何行も同じ事を書くのは、無駄でしょう?)
PGM (&PBACPT)
...略 ...
OVRDBF FUTGTMP MBR(&PBFUID) SHARE(*YES)
IF (&PBACPT='1') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD(*FILE)
ELSE IF (&PBACPT='2') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD((MDOUTC)(MDZIP ))
ELSE IF (&PBACPT='3') OPNQRYF FUTGTMP QRYSLT(&QRYSLT) KEYFLD((MDZIP )(MDOUTC))
|
1998/11/05 |