はじめに
これまでのステップで、COBOLの基本的な文法、制御構文、ファイル操作などを学んできました。お疲れ様でした!😊 このステップでは、これまでの知識を総動員して、実務でもよく使われる「売上集計プログラム」を作成するミニプロジェクトに挑戦します。
このプログラムは、日々の売上データが記録されたファイルを読み込み、商品ごとに売上金額を集計して、結果を別のファイルに出力するものです。COBOLが得意とするバッチ処理の典型的な例です。さっそく仕様を確認していきましょう!💻
プログラムの仕様
今回の売上集計プログラムの仕様は以下の通りです。
1. 入力ファイル(売上データ)
入力ファイル (SALES-IN.DAT
) は、1レコードが1つの売上明細を表すシーケンシャルファイルです。各レコードのレイアウトは以下の通りです。(固定長レコード)
項目名 | 桁数 (Bytes) | データ型 | 内容 |
---|---|---|---|
商品コード | 5 | 文字 (PIC X(5) ) |
商品を一意に識別するコード |
数量 | 3 | 数字 (PIC 9(3) ) |
販売した数量 |
単価 | 5 | 数字 (PIC 9(5) ) |
商品の単価 |
入力データ例:
A000101010000
B000200505000
A000100220000
C000302000800
B000200305000
2. 出力ファイル(集計結果)
出力ファイル (SALES-OUT.DAT
) には、商品コードごとの合計売上金額を集計した結果を書き込みます。各レコードのレイアウトは以下の通りです。
項目名 | 桁数 (Bytes) | データ型 | 内容 |
---|---|---|---|
商品コード | 5 | 文字 (PIC X(5) ) |
商品を一意に識別するコード |
合計売上金額 | 8 | 数字 (PIC 9(8) ) |
商品ごとの合計売上金額 (数量 * 単価 の合計) |
上記入力データに対する期待される出力データ例:
A00010030000
B00020040000
C00030016000
補足: 集計処理を行うためには、入力ファイルが商品コード順にソートされている必要があります。今回は事前にソートされている前提としますが、実務ではSORT文を使ってプログラム内でソートすることもよくあります(Step 4で学習しましたね!)。
3. 処理内容
- 入力ファイル (
SALES-IN.DAT
) を開きます。 - 出力ファイル (
SALES-OUT.DAT
) を開きます。 - 入力ファイルから1レコード読み込みます。
- ファイルの終わり (EOF) になるまで、以下の処理を繰り返します。
- 現在のレコードの商品コードを保持します。
- 同じ商品コードのレコードを続けて読み込みながら、売上金額(数量 * 単価)を合計します。
- 商品コードが変わるか、ファイルの終わりに達したら、保持していた商品コードと計算した合計売上金額を出力ファイルに書き込みます。
- 入力ファイルと出力ファイルを閉じます。
この処理方法は「コントロールブレイク(制御切れ)」と呼ばれる古典的なバッチ処理のパターンの一つです。
COBOLプログラムの構造とコード例
それでは、上記の仕様を満たすCOBOLプログラムの構造と、各DIVISIONのコード例を見ていきましょう。
1. IDENTIFICATION DIVISION
プログラムの名前を定義します。
IDENTIFICATION DIVISION.
PROGRAM-ID. SALES-SUMMARY.
AUTHOR. COBOL-LEARNER.
2. ENVIRONMENT DIVISION
プログラムが使用するファイル(入力・出力)を定義します。
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SALES-IN-FILE ASSIGN TO "SALES-IN.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT SALES-OUT-FILE ASSIGN TO "SALES-OUT.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT
句で論理ファイル名 (SALES-IN-FILE
,SALES-OUT-FILE
) と物理ファイル名 ("SALES-IN.DAT"
,"SALES-OUT.DAT"
) を関連付けます。ORGANIZATION IS LINE SEQUENTIAL
は、テキストファイル(行区切り)として扱うことを示します。環境によってはORGANIZATION IS SEQUENTIAL
などが適切な場合もあります。
3. DATA DIVISION
プログラム内で使用するデータ項目(ファイルレコード、作業用変数など)を定義します。
FILE SECTION
ENVIRONMENT DIVISION
で定義したファイルのレコード構造を定義します。
DATA DIVISION.
FILE SECTION.
FD SALES-IN-FILE.
01 SALES-IN-REC.
05 SI-PROD-CODE PIC X(5).
05 SI-QUANTITY PIC 9(3).
05 SI-UNIT-PRICE PIC 9(5).
FD SALES-OUT-FILE.
01 SALES-OUT-REC.
05 SO-PROD-CODE PIC X(5).
05 SO-TOTAL-AMOUNT PIC 9(8).
FD
(File Description) でファイル名を指定します。01
レベルでレコード全体の名前 (SALES-IN-REC
,SALES-OUT-REC
) を定義します。05
レベルで各項目を定義し、PIC
句でデータ型と桁数を指定します。
WORKING-STORAGE SECTION
ファイルのレコード以外で、プログラム内で使用する変数を定義します。
WORKING-STORAGE SECTION.
* 作業用変数
01 WK-VARIABLES.
05 WK-PROD-CODE PIC X(5).
05 WK-TOTAL-AMOUNT PIC 9(8) VALUE ZERO.
05 WK-SUB-AMOUNT PIC 9(8).
* ファイル終了フラグ
01 EOF-FLAG PIC X(1) VALUE 'N'.
88 EOF VALUE 'Y'.
WK-PROD-CODE
: 現在処理中の商品コードを保持します。WK-TOTAL-AMOUNT
: 商品ごとの合計金額を計算するために使用します。VALUE ZERO
で初期値を0に設定します。WK-SUB-AMOUNT
: 1レコード分の売上金額(数量 * 単価)を一時的に格納します。EOF-FLAG
: 入力ファイルの終了を判定するためのフラグです。VALUE 'N'
で初期値を ‘N’ (Not End Of File) に設定します。88
レベル項目 (条件名) を使うと、IF EOF
のように直感的に記述できます。
4. PROCEDURE DIVISION
プログラムの具体的な処理手順を記述します。
PROCEDURE DIVISION.
MAIN-PROC.
* 初期処理
PERFORM OPEN-FILES.
* 最初のレコード読み込み
PERFORM READ-SALES-IN.
* ファイルの終わりまで主処理を繰り返す
PERFORM UNTIL EOF
MOVE SI-PROD-CODE TO WK-PROD-CODE
MOVE ZERO TO WK-TOTAL-AMOUNT
* 同じ商品コードの間、集計処理を繰り返す
PERFORM UNTIL EOF OR SI-PROD-CODE NOT = WK-PROD-CODE
COMPUTE WK-SUB-AMOUNT = SI-QUANTITY * SI-UNIT-PRICE
ADD WK-SUB-AMOUNT TO WK-TOTAL-AMOUNT
PERFORM READ-SALES-IN
END-PERFORM
* 集計結果の出力
PERFORM WRITE-SALES-OUT
END-PERFORM.
* 終了処理
PERFORM CLOSE-FILES.
* プログラム終了
STOP RUN.
* --- サブルーチン ---
OPEN-FILES.
OPEN INPUT SALES-IN-FILE.
OPEN OUTPUT SALES-OUT-FILE.
READ-SALES-IN.
READ SALES-IN-FILE
AT END MOVE 'Y' TO EOF-FLAG
END-READ.
WRITE-SALES-OUT.
MOVE WK-PROD-CODE TO SO-PROD-CODE.
MOVE WK-TOTAL-AMOUNT TO SO-TOTAL-AMOUNT.
WRITE SALES-OUT-REC.
CLOSE-FILES.
CLOSE SALES-IN-FILE.
CLOSE SALES-OUT-FILE.
- 処理を
PERFORM
文でサブルーチン化(段落化)することで、MAIN-PROC
が読みやすくなります。 OPEN-FILES
: 入力ファイルと出力ファイルをそれぞれINPUT
モード、OUTPUT
モードで開きます。READ-SALES-IN
: 入力ファイルを1レコード読み込みます。AT END
句で、ファイルの終わりに達したらEOF-FLAG
に ‘Y’ を設定します。MAIN-PROC
内のPERFORM UNTIL EOF
ループ: ファイルの終わりまで処理を繰り返します。- 内部の
PERFORM UNTIL EOF OR SI-PROD-CODE NOT = WK-PROD-CODE
ループ: これがコントロールブレイクの核心部分です。商品コードが変わるか、ファイルが終わるまで、同じ商品コードのデータの金額(COMPUTE WK-SUB-AMOUNT = SI-QUANTITY * SI-UNIT-PRICE
)をWK-TOTAL-AMOUNT
に加算(ADD
)し、次のレコードを読み込みます。 WRITE-SALES-OUT
: 商品コードが変わったタイミング(または最後の商品の処理後)で、保持していた商品コード(WK-PROD-CODE
)と合計金額(WK-TOTAL-AMOUNT
)を出力レコードに転記(MOVE
)し、ファイルに書き込み(WRITE
)ます。CLOSE-FILES
: 処理が完了したらファイルを閉じます。STOP RUN
: プログラムの実行を終了します。
実行と確認
作成したCOBOLプログラムを実行してみましょう。
1. 準備
- 上記のCOBOLコードをテキストエディタで作成し、
SALES-SUMMARY.cbl
のような名前で保存します。(拡張子は.cob
など環境に合わせてください) - 仕様で示したフォーマットで、入力データファイル
SALES-IN.DAT
を作成します。(商品コード順にソートされていることを確認してください)
2. コンパイル
GnuCOBOL (旧称 OpenCOBOL) を使用している場合、ターミナル(コマンドプロンプト)で以下のコマンドを実行してコンパイルします。
cobc -x -free SALES-SUMMARY.cbl
-x
: 実行可能ファイルを生成するオプションです。-free
: フリーフォーマット形式のソースコードであることを指定します。(固定フォーマットの場合は不要です)- コンパイルが成功すると、実行可能ファイル (Windowsなら
SALES-SUMMARY.exe
, Linux/macOSならSALES-SUMMARY
) が生成されます。
3. 実行
生成された実行可能ファイルを実行します。
Windowsの場合:
.\SALES-SUMMARY.exe
Linux/macOSの場合:
./SALES-SUMMARY
プログラムが正常に実行されると、カレントディレクトリに SALES-OUT.DAT
ファイルが作成されます。
4. 結果確認
生成された SALES-OUT.DAT
ファイルを開き、内容が期待通り(仕様で示した出力データ例と同じ)になっているか確認してください。商品コードごとに売上金額が正しく集計されていれば成功です!🎉
まとめと次のステップ
今回は、ミニプロジェクトとして売上集計プログラムを作成しました。入力ファイルの読み込み、データ加工(計算)、集計処理(コントロールブレイク)、出力ファイルの書き込みといった、COBOLの基本的な要素を組み合わせる実践的な経験ができたと思います。
このプログラムをベースに、さらに以下のような改良を加えることも考えられます。
- 入力データのフォーマットチェックやエラーハンドリングを追加する。
- 集計キーを複数にする(例:店舗コード+商品コード)。
- 出力ファイルだけでなく、画面にも結果を表示する。
- SORT文を使って、プログラム内で入力データをソートする。
これでStep 7の最初のミニプロジェクトは完了です!この調子で、次の「簡易マスタ検索プログラムの作成」にも挑戦してみましょう。💪
参考情報:
- GnuCOBOL 公式サイト: https://www.gnu.org/software/gnucobol/
- GnuCOBOL Programmer’s Guide: 公式サイト内や検索エンジンで見つけることができます。詳細な文法や機能について知りたい場合に参照してください。
コメント