【実務・中級編】PIC ‘9’と’Z’による数値編集の挙動差異 – PL/Iの基本構文とデータ制御実践ガイド

「おい、〇〇、ちょっといいか? 今日はPL/Iのピクチャ編集、特に『9』と『Z』の使い分けについて、とことん掘り下げてみよう。これ、一見すると地味な話に聞こえるかもしれないが、基幹システムの帳票やファイル出力で、まさに命綱となる部分なんだ。ここを疎かにすると、金額がずれて表示されたり、ゼロが表示されなかったりして、顧客からの信頼を失いかねない。実際に現場で、この編集文字のちょっとした誤解が原因で、大規模な改修作業が発生したなんてケースも少なくないからな。」

PL/Iピクチャ編集の深淵:’9’と’Z’、その使い分けと落とし穴

「君たちがこれから触れるメインフレームのPL/Iプログラムには、きっと数十年分の知恵と、時には先人たちの涙と汗が凝縮されている。その中でも、数値の表示フォーマットを制御する『PIC』句は、一見すると単純だが、その裏には奥深いルールと、思わぬ落とし穴が潜んでいるんだ。特に『9』と『Z』、この二つの編集文字の使い分けは、基幹システムの保守・開発において非常に重要になる。今日は、その本質と、現場で役立つ実践的な知識を伝授しよう。」

1. PL/Iプログラムの基本構造:おさらいと今回の舞台設定

「まずは、今回の話を進める上でのPL/Iプログラムの基本構造を軽くおさらいしておこう。PL/Iは、`PACKAGE`で関連するプロシージャやデータ定義をまとめ、その中に`PROCEDURE OPTIONS(MAIN)`でエントリポイントとなるメインプロシージャを記述するのが一般的だ。こうすることで、モジュール性を高め、大規模なシステムでも管理しやすくなる。今回は、この構造の中で、入力ファイルを読み込み、数値を加工して出力する、典型的なバッチ処理を想定するぞ。」

PL/I
//
/ サンプルプログラム:PL/I ピクチャ編集 ‘9’ と ‘Z’ の挙動検証 /
/ 対象:PIC ‘9’ と ‘Z’ による数値編集の挙動差異 /
/ および符号付き数値の編集ルール /
//
TESTPICP: PACKAGE OPTIONS(MAIN); / PACKAGEでプログラム全体を囲む /

/ グローバルなデータ宣言や、共通ルーチンなどをここに配置できる /
/ 今回はメインプロシージャ内で完結するため、データ定義はメインプロシージャ内で行う /

/ ファイル定義: SYSINは入力、SYSPRINTは標準出力ファイル(帳票) /
DCL SYSIN FILE INPUT STREAM ENVIRONMENT(FB RECSIZE(80));
DCL SYSPRINT FILE OUTPUT STREAM PRINT ENVIRONMENT(F RECSIZE(133));

/ ONユニット定義: エラーハンドリングは基幹システムの基本中の基本だ /
ON ENDFILE(SYSIN)
BEGIN;
PUT SKIP LIST(‘— 入力ファイルの終端です —‘);
GO TO END_PROGRAM; / ファイル終端で処理を終了させる /
END;

ON CONVERSION
BEGIN;
PUT SKIP LIST(‘!!! データ変換エラーが発生しました !!!’);
PUT SKIP LIST(‘エラー発生箇所: ‘ || ONLOC() || ‘, 不正なデータ: ‘ || ONCHAR());
GO TO END_PROGRAM; / 変換エラーが発生したら異常終了させる /
END;

ON ERROR
BEGIN;
PUT SKIP LIST(‘!!! 一般エラーが発生しました !!!’);
PUT SKIP LIST(‘エラーコード: ‘ || ONCODE() || ‘, メッセージ: ‘ || ONMESSAGE());
GO TO END_PROGRAM; / その他のエラーも異常終了 /
END;

/ メインプロシージャ: プログラムのエントリポイント /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

/ 顧客レコードの構造定義 /
DCL 1 CUSTOMER_REC,
5 CUSTOMER_ID PIC ‘9(7)’, / 顧客ID (7桁数値) /
5 CUSTOMER_NAME CHAR(30) VARYING, / 顧客名 (可変長30文字) /
5 SALES_AMOUNT DECIMAL FIXED(9,2), / 売上金額 (DECIMAL固定小数点 9桁、小数点以下2桁) /
5 TAX_RATE DECIMAL FIXED(3,3); / 税率 (DECIMAL固定小数点 3桁、小数点以下3桁) /

/ 編集後の文字列を格納する変数群 /
DCL EDITED_AMOUNT_9 CHAR(15), / ‘9’ で編集した金額保持用 /
EDITED_AMOUNT_Z CHAR(15), / ‘Z’ で編集した金額保持用 /
EDITED_AMOUNT_SZ CHAR(15), / ‘S’ と ‘Z’ で編集した金額保持用 /
EDITED_AMOUNT_MINUS CHAR(15), / ‘-‘ で編集した金額保持用 /
EDITED_TAX_RATE_Z CHAR(10); / 税率を ‘Z’ で編集した保持用 /

/ ファイルオープン /
OPEN FILE(SYSIN);
OPEN FILE(SYSPRINT);

/ ヘッダ出力 /
PUT FILE(SYSPRINT) SKIP(2) LIST(‘ PL/I ピクチャ編集 ‘ || ”’9”’ || ‘ と ‘ || ”’Z”’ || ‘ の挙動検証 ‘);
PUT FILE(SYSPRINT) SKIP(2) EDIT(
‘顧客ID’, ‘顧客名’, ‘元金額’, ‘税率’,
‘9編集(999,999.99)’, ‘Z編集(ZZZ,ZZZ.99)’, ‘SZ編集(SZZ,ZZZ.99)’, ‘-編集(-,ZZZ,ZZZ.99)’, ‘税率Z編集(Z.ZZZ)’
)(A, A(30), A(10), A(7), A(19), A(19), A(19), A(21), A(15)); / ヘッダの桁数を調整 /
PUT FILE(SYSPRINT) SKIP EDIT(
‘——‘, ‘——————————‘, ‘———-‘, ‘——-‘,
‘——————-‘, ‘——————-‘, ‘——————-‘, ‘———————‘, ‘—————‘
)(A, A, A, A, A, A, A, A, A);

/ メイン処理ループ /
DO WHILE(‘1’B); / 無限ループ。ON ENDFILEでGO TO END_PROGRAMへ /

/ SYSINから1レコード読み込み /
/ 入力データは固定長で、F形式(フォーマット記述)でDECIMAL値として解釈させる /
GET FILE(SYSIN) EDIT(CUSTOMER_ID, CUSTOMER_NAME, SALES_AMOUNT, TAX_RATE)
(R(INPUT_FORMAT));

/ — ここからピクチャ編集の実行 — /

/ 1. ‘9’ による編集: ゼロは強制表示 /
/ PIC ‘999,999.99’ の場合、常に指定された桁数で表示され、 /
/ 不足する桁には ‘0’ が埋められる。 /
/ 例: 1234.56 -> “001,234.56” /
/ 例: 0.00 -> “000,000.00” /
EDITED_AMOUNT_9 = CUSTOMER_REC.SALES_AMOUNT PIC ‘999,999.99’;

/ 2. ‘Z’ による編集: 先頭ゼロを抑制 /
/ PIC ‘ZZZ,ZZZ.99′ の場合、整数部の先行ゼロは空白に置き換えられる。 /
/ 小数点以下は ’99’ なので、常に2桁表示される。 /
/ 値がゼロ (0.00) の場合、” 0.00″ となる。 /
/ もし ‘ZZZ,ZZZ.ZZ’ とすると、値がゼロなら全て空白 (” “) となる。 /
EDITED_AMOUNT_Z = CUSTOMER_REC.SALES_AMOUNT PIC ‘ZZZ,ZZZ.99’;

/ 3. ‘S’ と ‘Z’ を組み合わせた編集: 符号も抑制対象に含める /
/ ‘S’ は符号の有無を示すが、’Z’ と組み合わせると符号も抑制の対象となる。 /
/ 正の値の場合、符号は表示されない。負の値の場合のみ ‘-‘ が表示される。 /
/ 例: -123.45 -> “- 123.45″ /
/ 例: 0.00 -> ” ” (全Zの場合、Sも抑制される) /
EDITED_AMOUNT_SZ = CUSTOMER_REC.SALES_AMOUNT PIC ‘SZZ,ZZZ.99’;

/ 4. ‘-‘ を使った編集: 負の場合のみ符号を表示、先頭ゼロ抑制 /
/ ‘-‘ は常に左端に配置され、負の値の場合のみ ‘-‘ が表示される。 /
/ 正の値の場合は空白が埋められる。他の ‘Z’ と同様に先頭ゼロは抑制される。 /
/ 例: -123.45 -> “- 123.45″ /
/ 例: 123.45 -> ” 123.45″ /
EDITED_AMOUNT_MINUS = CUSTOMER_REC.SALES_AMOUNT PIC ‘-,ZZZ,ZZZ.99’;

/ 5. 税率の編集例: 小数点以下のゼロ抑制も含む /
/ PIC ‘Z.ZZZ’ の場合、整数部のゼロと小数点以下の先行ゼロを抑制。 /
/ 値が 0.080 -> ” .080″ /
/ 値が 0.000 -> ” ” (全てゼロなので空白) /
/ 値が 1.000 -> ” 1.000″ /
EDITED_TAX_RATE_Z = CUSTOMER_REC.TAX_RATE PIC ‘Z.ZZZ’;

/ — 編集結果を出力 — /
PUT FILE(SYSPRINT) SKIP EDIT(
CUSTOMER_ID,
CUSTOMER_NAME,
FIXED(CUSTOMER_REC.SALES_AMOUNT, 9, 2), / 元のDECIMAL値をそのまま表示 (F形式は数値として出力) /
FIXED(CUSTOMER_REC.TAX_RATE, 1, 3), / 元のDECIMAL値をそのまま表示 /
EDITED_AMOUNT_9,
EDITED_AMOUNT_Z,
EDITED_AMOUNT_SZ,
EDITED_AMOUNT_MINUS,
EDITED_TAX_RATE_Z
)(A, A(30), F(10,2), F(7,3), A(19), A(19), A(19), A(21), A(15));

END; / DO WHILE /

END_PROGRAM: / 処理終了ラベル /
CLOSE FILE(SYSIN);
CLOSE FILE(SYSPRINT);
RETURN; / メインプロシージャを終了 /

/ 入力データのフォーマット定義 (F形式は数値データ向け) /
INPUT_FORMAT: FORMAT(
COL(1) A(7), / 顧客ID (文字として読み込む) /
COL(8) A(30), / 顧客名 (文字として読み込む) /
COL(38) F(9,2), / 売上金額 (9桁、小数点以下2桁の数値として読み込む) /
COL(47) F(4,3) / 税率 (4桁、小数点以下3桁の数値として読み込む) /
);

END MAIN_PROC; / メインプロシージャの終了 /
END TESTPICP; / PACKAGEの終了 /

2. PIC ‘9’ の挙動と哲学:数値は全て見えるべきだ!

「『9』はな、プログラマの意図が明確で、一切の曖昧さを許さない文字だ。指定した桁数分の数値を強制的に表示する。もし数値が指定桁数に満たなければ、先行する桁は『0』で埋められる。小数点もカンマも、指定した位置にそのまま表示される。

これは、特に会計システムや金融システムで非常に重要になる。『000,000.00』と表示されるべき金額が、勝手にゼロ抑制されて『 . 』と表示されてしまったら、それはもはや金額ではない。帳票を見て、『この行の金額はゼロだ』と明確に判断できることが求められるんだ。」

出力例: (上記のコードと入力データ `0000003株式会社山田 000000.000000`)
`9編集(999,999.99)`: `000,000.00`

「見ての通り、ゼロはゼロとして、きちんと指定されたフォーマットで表示される。これが『9』の哲学なんだ。決して『空白』にはならない。数値は、その値が持つ全ての情報を正確に伝えるべきだ、という強い意志が込められている。」

3. PIC ‘Z’ の魅力と注意点:スマートなゼロ抑制、しかし油断は禁物

「さて、次に『Z』だ。これは『Zero Suppress』、つまりゼロ抑制の『Z』だ。先行するゼロを空白に置き換えて、より見やすい表示を実現するのが目的だ。例えば、顧客番号や伝票番号のように、『000123』よりも『123』と表示された方が、直感的に理解しやすい場合に使われる。」

出力例: (入力データ `0000001太郎商店 001234.560080`)
`Z編集(ZZZ,ZZZ.99)`: ` 1,234.56`

「どうだ? 先頭のゼロが空白になり、すっきりしただろう? しかし、ここからが本番だ。この『Z』、一見便利そうに見えるが、実はとんでもない落とし穴が潜んでいるんだ。」

3.1. 全て『Z』の場合の挙動:ゼロは空白になる!

「最も注意すべきは、ピクチャ句の全ての桁を『Z』で指定した場合だ。例えば、`PIC ‘ZZZ,ZZZ.ZZ’` のように。この場合、もし元の数値が『0.00』だったとすると、結果は全て空白になるんだ。」

出力例: (もし `EDITED_AMOUNT_Z` を `PIC ‘ZZZ,ZZZ.ZZ’` にした場合の `0.00` の出力)
`Z編集(ZZZ,ZZZ.ZZ)`: ` ` (12桁全て空白)

「これが何を引き起こすか想像できるか? 帳票に金額が印刷される際に、『ゼロ円』であるはずの項目が空白になってしまうんだ。これでは、本当にデータが存在しないのか、それともゼロなのかが判別できず、利用者を混乱させてしまう。特に金額欄では、これは絶対に避けなければならない。だから、金額や数量といった重要な数値には、末尾の数桁に『9』を組み合わせるのが常套手段なんだ。」

3.2. 『Z』と『9』の組み合わせ:スマートなゼロ表示

「先ほどのコード例では、`PIC ‘ZZZ,ZZZ.99’` を使っていたな。この『Z』と『9』の組み合わせが、最も現場で使われるパターンの一つだ。整数部の先行ゼロは抑制しつつも、小数点以下は『99』で強制表示されるため、たとえ数値が『0.00』であっても、『 0.00』と表示される。これにより、『ゼロ円』であることが明確にわかるようになる。」

出力例: (入力データ `0000003株式会社山田 000000.000000`)
`Z編集(ZZZ,ZZZ.99)`: ` 0.00`

「素晴らしい。これが、ゼロ抑制とゼロ表示のバランスだ。この使い分けを誤ると、後々のトラブルに直結するから、肝に銘じておけ。」

4. 符号付き数値の編集ルールと罠

「数値には、正の数だけでなく、負の数も存在する。PL/Iのピクチャ句では、この符号の表示方法も細かく制御できるんだ。『S』、『-』、『+』、そして『CR』や『DB』といった文字が使われる。」

  • S (Sign): 符号位置を示し、数値が負なら `-`、正なら `+` または空白を表示する。`Z`と組み合わせると、符号も抑制の対象になる。
  • – (Minus): 負の場合のみ `-` を表示し、正の場合は空白を埋める。
  • + (Plus): 正の場合 `+`、負の場合 `-` を表示する。
  • CR (Credit): 負の場合に `CR` を表示し、正の場合は空白を埋める。(会計でよく使われる)
  • DB (Debit): 負の場合に `DB` を表示し、正の場合は空白を埋める。(会計でよく使われる)

「ここでは、特に『S』と『-』、そして『Z』との組み合わせに焦点を当ててみよう。」

4.1. PIC ‘SZZ,ZZZ.99’ の挙動:符号も抑制される!

「『S』は符号の位置を示すが、もしその前の桁が全て『Z』でゼロ抑制されている場合、符号自体も抑制の対象になる。つまり、正の値であれば符号は表示されず、負の値の場合のみ『-』が表示されることになる。これは『-』ピクチャ文字と似たような挙動だが、『S』の場合は符号が最左端に位置する。」

出力例: (入力データ `0000002花子物産 -000005.000050`)
`SZ編集(SZZ,ZZZ.99)`: `- 5.00`

出力例: (入力データ `0000003株式会社山田 000000.000000`)
`SZ編集(SZZ,ZZZ.99)`: ` ` (全てゼロなので空白)

「『S』はあくまで『符号の位置』を示すだけで、先行ゼロ抑制の効果は『Z』に任せる、と理解するといい。そして、その『Z』が全てを空白にしてしまう場合、符号も道連れになる、というわけだ。」

4.2. PIC ‘-,ZZZ,ZZZ.99’ の挙動:符号が左端に固定、負のみ表示

「一方、『-』ピクチャ文字は、その文字自体が符号の表示を制御する。これは常に左端に配置され、数値が負の場合にだけ『-』が表示される。正の場合はその位置に空白が埋められる。これも『Z』と組み合わせることで、先行ゼロ抑制の効果と両立できる。」

出力例: (入力データ `0000002花子物産 -000005.000050`)
`-編集(-,ZZZ,ZZZ.99)`: `- 5.00`

出力例: (入力データ `0000001太郎商店 001234.560080`)
`-編集(-,ZZZ,ZZZ.99)`: ` 1,234.56` (正の数なので符号は表示されない)

「『S』と『-』は似ているが、細かな挙動が違う。特に桁合わせや帳票デザインの要件によっては、どちらを使うべきか慎重に選ぶ必要があるぞ。そして、最も重要なのは、ピクチャ編集はあくまで文字への変換であり、元の数値データ型とは異なるということだ。変換結果の文字列が格納される変数 (`EDITED_AMOUNT_9` など) の長さが、ピクチャ句で指定した文字数と一致しているか、常に確認すること。もし編集結果が変数の長さを超えると、`ON SIZE` や `ON CONVERSION` などのONユニットが起動する可能性があるからな。」

5. まとめ:現場で活かすPL/Iピクチャ編集の極意

「さて、ここまで『9』と『Z』、そして符号付き数値の編集について見てきた。最後に、君たちが現場でこの知識をどう活かすか、その極意を伝えておこう。」

1. 金額、数量には『9』を基本に!

  • ゼロも必ず表示させることで、誤読を防止する。
  • `PIC ‘999,999.99’` のように、適切なカンマや小数点を加えることで、可読性を高める。

2. ID、コードには『Z』を!

  • `PIC ‘ZZZ999’` のように、先行ゼロを抑制し、重要な末尾桁は強制表示させることで、見やすさと情報の正確性を両両立させる。
  • 全て『Z』は極力避ける! ゼロが完全に空白になる挙動は、特に帳票では避けるべきだ。

3. 符号の扱いは明確に!

  • 『S』、『-』、『+』、『CR』、『DB』の中から、帳票の要件や会計ルールに合致するものを選択する。
  • 特に『S』と『Z』の組み合わせが、符号も抑制対象になることを理解しておくこと。

4. 変数の長さに注意!

  • ピクチャ句で編集された文字列を格納する `CHAR` 型変数は、常にピクチャ句の文字数以上の長さを確保すること。オーバーフローは思わぬバグの温床となる。

5. ONユニットは必ず設定!

  • `ON CONVERSION` や `ON SIZE` など、データ変換や桁あふれが発生した場合のハンドリングは必須だ。基幹システムでは、どんな小さなエラーも見逃してはならない。

「PL/Iのピクチャ編集は、単なるフォーマット指定ではない。それは、システムが表現するビジネス情報そのものの信頼性を左右する、極めて重要な要素なんだ。君たちがこれから触るレガシーコードにも、こういった細やかな配慮が込められているはずだ。先輩たちがなぜそのピクチャ句を選んだのか、その意図を汲み取れるようになれば、一人前のメインフレームエンジニアとして、また一歩成長したと言えるだろう。頑張れよ!」

タイトルとURLをコピーしました