ここでは、SIT COBOLがサポートしている、順ファイル・行順ファイル・索引ファイルについて具体的な書き方について記述する。
順ファイル(Sequential File)とは、レコード(データのひとまとまり)を順番に格納し、順番通りにアクセスするファイル形式である。データは一列に並んでおり、先頭から順番に読み書きすることで処理される。
この形式の最大の特徴は、データへのアクセスが順序通りにしか行えない点である。特定のレコードに直接アクセスすることはできず、常に先頭から順番に処理を行う必要がある。
順ファイルは、以下のような用途で広く使用されている。
順ファイルの主な特徴は以下の通り:
一方で、特定のレコードへの直接アクセスができないという制約もあるため、用途に応じた使い分けが求められる。
まず、順ファイルを作成する例を見ていく。
サンプルとして作成するファイルは、5種類の果物の名前とその数量を持つシンプルなファイルである。
(サンプルプログラム名:順ファイルの作成例.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE001.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt"
000060 ORGANIZATION IS SEQUENTIAL.
000070 DATA DIVISION.
000080 FILE SECTION.
000090 FD 果物ファイル.
000100 01 果物レコード.
000110 02 名前 PIC N(10).
000120 02 数量 PIC 9(5).
000130 WORKING-STORAGE SECTION.
000140 01 果物データ.
000150 02 PIC N(10) VALUE NC"リンゴ".
000160 02 PIC 9(5) VALUE 10.
000170 02 PIC N(10) VALUE NC"オレンジ".
000180 02 PIC 9(5) VALUE 5.
000190 02 PIC N(10) VALUE NC"メロン".
000200 02 PIC 9(5) VALUE 20.
000210 02 PIC N(10) VALUE NC"バナナ".
000220 02 PIC 9(5) VALUE 8.
000230 02 PIC N(10) VALUE NC"イチゴ".
000240 02 PIC 9(5) VALUE 12.
000250 01 果物データ2 REDEFINES 果物データ.
000260 02 果物テーブル OCCURS 5.
000270 03 名前 PIC N(10).
000280 03 数量 PIC 9(5).
000290 01 I PIC 9.
000300 PROCEDURE DIVISION.
000310 MAIN00.
000320* ファイルのオープン
000330 OPEN OUTPUT 果物ファイル.
000340* 5つの果物データをファイルに書き出し
000350 PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000360 MOVE 果物テーブル(I) TO 果物レコード
000370 WRITE 果物レコード
000380 END-PERFORM.
000390* ファイルのクローズ
000400 CLOSE 果物ファイル.
000410 STOP RUN.
まず、果物ファイルの定義は、環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)の中にSELECT句を書くことによって行う。
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt"
000060 ORGANIZATION IS SEQUENTIAL
000070 ACCESS MODE IS SEQUENTIAL.
ファイル名は、SELECT句の直後に書く。また、ファイル編成が順編成であることは、「ORGANIZATION IS SEQUENTIAL」にて宣言する。(ORGANIZATION句を書かない場合の既定値は順編成なので書かなくともよい)
また、アクセスモードについてはACCESS MODE句で指定するが、順ファイルの場合は順呼出し(SEQUENTIAL)のみである。(ACCESS句を書かない場合の既定値は順呼出しなので書かなくともよい)
また、ファイルの実体については、「ASSIGN TO」
の直後に記述する。
ここでは”./果物ファイル.txt”が指定されているので、カレントディレクトリ配下(*1)に「果物ファイル.txt」が作られる。
(*1) 実行するCOBOLプログラムが存在するディレクトリがカレントディレクトリとなる。絶対パスも指定可である。
なお、ファイルの実体を環境変数によって指定することも可能である。例えば、“FILE_PATH”という環境変数にファイルの実体が指定されている場合は、次のように指定する。
000050 SELECT 果物ファイル ASSIGN TO "FILE_PATH"
000060 ORGANIZATION IS SEQUENTIAL
000070 ACCESS MODE IS SEQUENTIAL.
SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれた定数と同じ名前の環境変数が存在するか確認し、存在する場合にはその環境変数からファイルを実体を取得し存在しない場合は、書かれた定数の値がファイルの実体であるとみなす。
さらには、次のようにデータ名で指定することも可能である。例えば、ファイルパスというデータ名でファイルの実体を指定するのであれば、次のように指定する。
000050 SELECT 果物ファイル ASSIGN TO ファイルパス
000060 ORGANIZATION IS SEQUENTIAL
000070 ACCESS MODE IS SEQUENTIAL.
:
000000 WORKING-STORAGE SECTION.
000000 01 ファイルパス PIC X(255).
:
000000 MOVE "./果物ファイル.txt" TO ファイルパス.
000000 OPEN OUTPUT 果物ファイル.
:
SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれたデータ名’ファイルパス’の値をファイルの実体であるとみなす。
一方、ファイルがどのようなレコード構造を持つかは、データ部(DATA部)の、ファイル節(FILE節)に記述する。
000080 DATA DIVISION.
000090 FILE SECTION.
000100 FD 果物ファイル.
000110 01 果物レコード.
000120 02 名前 PIC N(10).
000130 02 数量 PIC 9(5).
FDの次にファイル名を記述し、その次にレコード構造を記述する。
ここでは、’名前’というデータ名と、’数量’というデータ名を持つ’果物レコード’が定義されている。果物レコードの大きさは、日本語10文字と英数字5文字(5バイト)を足し合わせた大きさである。
(注意) SIT COBOLは、ファイル中のレコードには、用途がDISPLAYである英数字項目、英数字編集項目、外部十進項目、数字編集項目、日本語項目、日本語編集項目のみしか定義できないようにしている。これは、COBOLを学習するにあたり、ファイルの中身をエディタ等で開いて確認できるようにすることに優先順位をおいているためである。
ファイルを開くには、OPEN文を使用する。
000330* ファイルのオープン
000340 OPEN OUTPUT 果物ファイル.
オープンモードは、OPEN文の直後に記述する。この場合は、OUTPUTモードなので、ファイルが存在すれば上書きをし、存在しなければ1から作成することを指示している。
ファイルにデータを書き込むには、WRITE文を使用する。
下記は、果物テーブル(1)~果物テーブル(5)までのデータを順次果物レコードに転記し、WRITE文でレコードの内容をファイルに出力している。
000350* 5つの果物データをファイルに書き出し
000360 PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000370 MOVE 果物テーブル(I) TO 果物レコード
000380 WRITE 果物レコード
000390 END-PERFORM.
MOVE文とWRITE文は次のようにFROM指定を使用して1文にすることもできる。
00370 WRITE 果物レコード FROM 果物テーブル(I)
ファイルを閉じるには、CLOSE文を使用する。
000400* ファイルのクローズ
000410 CLOSE 果物ファイル.
上記のプログラムを実行すると次のようなファイルが作成される。
(Windows上のコマンドプロンプトでcatコマンドで確認した例。“□”は日本語の空白を示す)
> cat .\果物ファイル.txt
リンゴ□□□□□□□00010オレンジ□□□□□□00005メロン□□□□□□□00020バナナ□□□□□□□00008イチゴ□□□□□□□00012
>
次に、順ファイルを読み出す例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.txt”である。
(サンプルプログラム名:順ファイルの入力例.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE002.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt".
000060 DATA DIVISION.
000070 FILE SECTION.
000080 FD 果物ファイル.
000090 01 果物レコード.
000100 02 名前 PIC N(10).
000110 02 数量 PIC 9(5).
000120 WORKING-STORAGE SECTION.
000130 01 ヘッダ.
000140 02 PIC N(10) VALUE NC"果物名".
000150 02 PIC N(3) VALUE NC"個数".
000160 01 罫線 PIC X(25) VALUE ALL "-".
000170 01 果物データ.
000180 02 果物名 PIC N(10).
000190 02 個数 PIC ZZZZ9.
000200 01 合計データ.
000210 02 PIC N(10) VALUE NC"合計".
000220 02 合計 PIC ZZZZ9.
000230 PROCEDURE DIVISION.
000240 MAIN00.
000250* ファイルのオープン
000260 OPEN INPUT 果物ファイル.
000270* 初期化
000280 MOVE 0 TO 合計.
000290* ヘッダ出力
000300 DISPLAY ヘッダ.
000310 DISPLAY 罫線.
000320* ファイルから果物データをAT ENDとなるまで読み込む
000330 PERFORM FOREVER
000340 READ 果物ファイル
000350 AT END
000360 EXIT PERFORM
000370 NOT AT END
000380 MOVE 名前 OF 果物レコード TO 果物名
000390 MOVE 数量 OF 果物レコード TO 個数
000400 DISPLAY 果物データ
000410 ADD 数量 OF 果物レコード TO 合計
000420 END-READ
000430 END-PERFORM.
000440* フッタの出力
000450 DISPLAY 罫線.
000460 DISPLAY 合計データ.
000470* ファイルのクローズ
000480 CLOSE 果物ファイル.
000490 STOP RUN.
ファイルの定義、ファイルのデータ後続については例(1)と同じなので省略する。
ファイルを開くには、OPEN文を使用する。
000250* ファイルのオープン
000260 OPEN INPUT 果物ファイル.
この場合は、INPUTモードで開いている。ファイルが存在しない場合にはエラーとなる。
ファイルからデータを読み込むには、READ文を使用する。
ここで、WRITE文に指定するのはレコード名であるのに対し、READ文に指定するのはファイル名であることに注意されたい。
下記は、FOREVER指定(無限指定)のPERFORM文によって繰り返し、果物ファイルから1件ずつレコードを読み込む。そして、AT ENDとなった時点(データが終了した時点)でPERFORM文から抜ける(EXIT PERFORM)。
000320* ファイルから果物データをAT ENDとなるまで読み込む
000330 PERFORM FOREVER
000340 READ 果物ファイル
000350 AT END
000360 EXIT PERFORM
000370 NOT AT END
000380 MOVE 名前 OF 果物レコード TO 果物名
000390 MOVE 数量 OF 果物レコード TO 個数
000400 DISPLAY 果物データ
000410 ADD 数量 OF 果物レコード TO 合計
000420 END-READ
000430 END-PERFORM.
レコードの読み込みが成功した場合は、NOT AT
END句の無条件文が実行される(000380-000410行)。
ここでは、果物レコードの名前と数量が、それぞれ’果物名’、’個数’に転記され、さらに数量が、’合計’に加算されている。すなわち、’合計’には最終的に全果物の合計数量が設定される。
なお、次のように、INTO指定のREAD文により、レコードの読み込みが成功したときにレコード領域のデータを転記することもできる。
000340 READ 果物ファイル INTO 果物データ
000350 AT END
000360 EXIT PERFORM
000370 NOT AT END
000400 DISPLAY 果物データ
000410 ADD 数量 OF 果物レコード TO 合計
000420 END-READ
ファイルを閉じるには、例(1)と同じくCLOSE文を使用する。
000470* ファイルのクローズ
000480 CLOSE 果物ファイル.
さて、このプログラムを走行させると、次のような帳票が出力される。
果物名 個数
-------------------------
リンゴ 10
オレンジ 5
メロン 20
バナナ 8
イチゴ 12
-------------------------
合計 55
先頭の見出しおよび罫線は以下の2つのDISPLAY文で出力されている。
000290* ヘッダ出力
000300 DISPLAY ヘッダ.
000310 DISPLAY 罫線.
続く明細データは次のDISPLAY文で出力されている。
000400 DISPLAY 果物データ
最後の罫線および合計行は次のDISPLAY文で出力されている。
000440* フッタの出力
000450 DISPLAY 罫線.
000460 DISPLAY 合計データ.
次に、順ファイルのレコードを書き換えたり削除したりする例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.txt”である。
以下のプログラムは、オレンジの数量を15に変更し、またバナナレコードを削除するプログラムである。
なお、000450行以降は、更新したデータ内容や削除がうまくいっているかを確認するために例(2)のプログラムのロジックを使用して帳票出力をしている。
(サンプルプログラム名:順ファイルの更新例.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. SEQFILE003.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.txt".
000060 DATA DIVISION.
000070 FILE SECTION.
000080 FD 果物ファイル.
000090 01 果物レコード.
000100 02 名前 PIC N(10).
000110 02 数量 PIC 9(5).
000120 WORKING-STORAGE SECTION.
000130 01 ヘッダ.
000140 02 PIC N(10) VALUE NC"果物名".
000150 02 PIC N(3) VALUE NC"個数".
000160 01 罫線 PIC X(25) VALUE ALL "-".
000170 01 果物データ.
000180 02 果物名 PIC N(10).
000190 02 個数 PIC ZZZZ9.
000200 01 合計データ.
000210 02 PIC N(10) VALUE NC"合計".
000220 02 合計 PIC ZZZZ9.
000230 PROCEDURE DIVISION.
000240 MAIN00.
000250* ファイルのオープン
000260 OPEN I-O 果物ファイル.
000270* ファイルから果物データをAT ENDとなるまで読み込む
000280 PERFORM FOREVER
000290 READ 果物ファイル
000300 AT END
000310 EXIT PERFORM
000320 END-READ
000330 IF 名前 OF 果物レコード = NC"オレンジ"
000340 MOVE 15 TO 数量 OF 果物レコード
000350 REWRITE 果物レコード
000360 END-IF
000370 IF 名前 OF 果物レコード = NC"バナナ"
000380 DELETE 果物ファイル
000390 END-IF
000400 END-PERFORM.
000410
000420* ファイルのクローズ
000430 CLOSE 果物ファイル.
000440
000450* 再オープン
000460 OPEN INPUT 果物ファイル.
000470
000480* 初期化
000490 MOVE 0 TO 合計.
000500* ヘッダ出力
000510 DISPLAY ヘッダ.
000520 DISPLAY 罫線.
000530* ファイルから果物データをAT ENDとなるまで読み込む
000540 PERFORM FOREVER
000550 READ 果物ファイル
000560 AT END
000570 EXIT PERFORM
000580 NOT AT END
000590 MOVE 名前 OF 果物レコード TO 果物名
000600 MOVE 数量 OF 果物レコード TO 個数
000610 DISPLAY 果物データ
000620 ADD 数量 OF 果物レコード TO 合計
000630 END-READ
000640 END-PERFORM.
000650* フッタの出力
000660 DISPLAY 罫線.
000670 DISPLAY 合計データ.
000680* ファイルのクローズ
000690 CLOSE 果物ファイル.
000700 STOP RUN.
ファイルと定義、レコード構造については例(1)(2)と同じであり省略する。
ファイルを開くには、OPEN文を使用する。
000250* ファイルのオープン
000260 OPEN I-O 果物ファイル.
この場合は、I-Oモードで開いている。ファイルのデータの中身を更新したり削除したりするときはI-Oモードで開く必要がある。ない、存在しない場合にはエラーとなる。
ファイルからデータを読み込むには、READ文を使用する。READ文については例(2)で触れており、ここでは省略する。
000290 READ 果物ファイル
000300 AT END
000310 EXIT PERFORM
000320 END-READ
データの更新を行うには、REWRITE文を使用する。
000330 IF 名前 OF 果物レコード = NC"オレンジ"
000340 MOVE 15 TO 数量 OF 果物レコード
000350 REWRITE 果物レコード
000360 END-IF
上記では、果物レコードの名前が”オレンジであるとき、数量を15に更新してから、REWRITE文を実行している。
REWRITE文にはWRITE文と同じくレコード名を指定する必要がある。
データを削除するには、DELETE文を使用する。
000370 IF 名前 OF 果物レコード = NC"バナナ"
000380 DELETE 果物ファイル
000390 END-IF
上記では、果物レコードの名前が”バナナであるとき、DELETE文を実行している。
DELETE文にはREAD文と同じくファイル名を指定する必要がある。
なお、順ファイルのレコードを削除できるのは SIT COBOLの特別な機能である。
ファイルを閉じるには、例(1)(2)と同じくCLOSE文を使用する。
000420* ファイルのクローズ
000430 CLOSE 果物ファイル.
さて、このプログラムを走行させると、データの更新・削除が行われたあと、000450行から再びファイルをINPUTモードでオープンしてレコードの読み込みを行っており、次のような帳票が出力される。
果物名 個数
-------------------------
リンゴ 10
オレンジ 15
メロン 20
イチゴ 12
-------------------------
合計 57
オレンジの個数が15に変更されており、またバナナデータが削除されているのがわかる。
相対ファイル(Relative
File)は、COBOLのファイル編成の一つであり、各レコードが相対レコード番号(Relative
Record Number)で識別される。
データの格納位置はレコード番号に基づいて直接アクセスできるため、順次アクセスだけでなく直接アクセスもサポートする。
相対ファイルは、レコード番号を使用してデータを直接または順番にアクセスするため、特定の用途に適している。
固定長データの管理
固定サイズのデータレコードを効率的に管理し、データベースのように特定のレコードにランダムアクセスできる。
特定レコードの更新・検索
レコード番号を指定して直接アクセスできるため、特定のレコードだけを素早く更新・削除できる。
データベースの簡易実装
小規模データベースとして使用されることがあり、簡単な索引や管理機能を代替できる。
順次処理とランダム処理の併用
順次アクセス(全レコードを順番に処理)とランダムアクセス(特定のレコードに直接アクセス)の両方をサポートするため、柔軟な処理が可能。
トランザクションログ
ログのように順番にデータを書き込みつつ、必要に応じて特定のレコードを直接検索する用途にも使用される。
SIT COBOLは、相対ファイルを未サポート(サポート予定あり)であり、機能についての説明はここまでに留める。
索引ファイル(Indexed File)は、COBOLにおけるファイル編成の一つであり、キー値を用いてレコードにアクセスする。各レコードには少なくとも1つの主キー(Primary Key)があり、必要に応じて複数の代替キー(Alternate Key)を持つことができる。
索引を使うことで、順次アクセス、ランダムアクセス、動的アクセスが可能となる。
索引ファイル(Indexed File)は、主キー(Primary Key)および代替キー(Alternate Key)を用いてデータにアクセスする仕組みを持つファイル編成形式である。主に以下の用途で利用される。
顧客情報管理システム
顧客ID(主キー)や顧客名(代替キー)でレコードを検索し、データを管理する。
商品在庫管理システム
商品コード(主キー)やカテゴリ(代替キー)を使用して在庫情報にアクセスする。
社員管理システム
社員番号(主キー)や部署名(代替キー)を使用して社員情報を検索・管理する。
会計・財務システム
請求書番号や取引先IDをキーとして取引データを管理する。
マスターファイル管理
顧客マスターや商品マスターなど、特定キーで識別されるレコードの管理。
データベースの代替
小規模なシステムでは、リレーショナルデータベースの代わりに索引ファイルが使用されることがある。
まず、順ファイル例として作成した”果物ファイル”を索引ファイルとして作成する例を見ていく。
(サンプルプログラム名:索引ファイルの作成例.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE001.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS SEQUENTIAL.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130 02 商品番号 PIC 9(3).
000140 02 名前 PIC N(10).
000150 02 数量 PIC 9(5).
000160 WORKING-STORAGE SECTION.
000170 01 果物データ.
000180 02 PIC 9(3) VALUE 101.
000190 02 PIC N(10) VALUE NC"リンゴ".
000200 02 PIC 9(5) VALUE 10.
000210 02 PIC 9(3) VALUE 102.
000220 02 PIC N(10) VALUE NC"オレンジ".
000230 02 PIC 9(5) VALUE 5.
000240 02 PIC 9(3) VALUE 103.
000250 02 PIC N(10) VALUE NC"メロン".
000260 02 PIC 9(5) VALUE 20.
000270 02 PIC 9(3) VALUE 104.
000280 02 PIC N(10) VALUE NC"バナナ".
000290 02 PIC 9(5) VALUE 8.
000300 02 PIC 9(3) VALUE 105.
000310 02 PIC N(10) VALUE NC"イチゴ".
000320 02 PIC 9(5) VALUE 12.
000330 01 果物データ2 REDEFINES 果物データ.
000340 02 果物テーブル OCCURS 5.
000350 03 商品番号 PIC 9(3).
000360 03 名前 PIC N(10).
000370 03 数量 PIC 9(5).
000380 01 I PIC 9.
000390 PROCEDURE DIVISION.
000400 MAIN00.
000410* ファイルのオープン
000420 OPEN OUTPUT 果物ファイル.
000430* 5つの果物データをファイルに書き出し
000440 PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000450 MOVE 果物テーブル(I) TO 果物レコード
000460 WRITE 果物レコード
000470 END-PERFORM.
000480* ファイルのクローズ
000490 CLOSE 果物ファイル.
000500 STOP RUN.
ファイルの定義は、順ファイルと同様に、環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)の中にSELECT句を書くことによって行う。
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS SEQUENTIAL.
ファイル名は、SELECT句の直後に書く。また、ファイル編成が索引編成であることは、「ORGANIZATION IS INDEXED」にて宣言する。
また、アクセスモードについてはACCESS MODE句で指定する。ここでは、順にデータを書き出しするだけなので、順呼出し(SEQUENTIAL)を指定している。
また、ファイルの実体については、「ASSIGN TO」 の直後に記述する。ここでは”./果物ファイル.sqlite3”が指定されているので、カレントディレクトリ配下(*1)に「果物ファイル.sqlite3」が作られる。
ここで、拡張子として「.sqlite3」を指定しているが、これは SIT COBOL が 索引ファイルを、SQLITE3データベースをベースとして作成しており、索引ファイルの実体がSQLITE3であることを明示するために指定している(*2)。しかし、実際には、拡張子は何を指定してもよい。
(*1)
実行するCOBOLプログラムが存在するディレクトリがカレントディレクトリとなる。絶対パスも指定可である。
(*2)
索引ファイルは、SQLITE3データベースでできているので、SQLITE3データベースをアクセスできるユーティリティーで索引ファイルのメンテナンス等を行うことができる。
索引ファイルにおいては、必ず主キーを指定する必要がある。主キーは「RECORD
KEY」句で指定する。
ここでは、’商品番号 OF
果物レコード’を指定している。果物レコードで修飾しているのは、商品番号というデータ名が他にも使われており、一意にする必要があるためである。
なお、ファイルの実体を環境変数によって指定することも可能である。例えば、“FILE_PATH”という環境変数にファイルの実体が指定されている場合は、次のように指定する。
000050 SELECT 果物ファイル ASSIGN TO "FILE_PATH"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS SEQUENTIAL.
SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれた定数と同じ名前の環境変数が存在するか確認し、存在する場合にはその環境変数からファイルを実体を取得し存在しない場合は、書かれた定数の値がファイルの実体であるとみなす。
さらには、次のようにデータ名で指定することも可能である。例えば、ファイルパスというデータ名でファイルの実体を指定するのであれば、次のように指定する。
000050 SELECT 果物ファイル ASSIGN TO ファイルパス
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS SEQUENTIAL.
:
000000 WORKING-STORAGE SECTION.
000000 01 ファイルパス PIC X(255).
:
000000 MOVE "./果物ファイル.sqlite3" TO ファイルパス.
000000 OPEN OUTPUT 果物ファイル.
:
SIT COBOLは、OPEN文の実行時、ASSIGN TOの直後に書かれたデータ名’ファイルパス’の値をファイルの実体であるとみなす。
一方、ファイルがどのようなレコード構造を持つかは、データ部(DATA部)の、ファイル節(FILE節)に記述する。
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130 02 商品番号 PIC 9(3).
000140 02 名前 PIC N(10).
000150 02 数量 PIC 9(5).
FDの次にファイル名を記述し、その次にレコード構造を記述する。ここでは、’商品番号’、’名前’、’数量’というデータ名を持つ’果物レコード’が定義されている。果物レコードの大きさは、外部10進数3文字(3バイト)と日本語10文字と英数字5文字(5バイト)を足し合わせた大きさである。
そして、商品番号が、主レコードキーである。商品である果物には果物を識別する商品番号がついているという想定である。当然のことながら、同じ番号の商品があることはなく、商品番号は重複不可である。
(注意) SIT COBOLは、ファイル中のレコードには、用途がDISPLAYである英数字項目、英数字編集項目、外部十進項目、数字編集項目、日本語項目、日本語編集項目のみしか定義できないようにしている。これは、COBOLを学習するにあたり、ファイルの中身をエディタ等で開いて確認できるようにすることに優先順位をおいているためである。
ファイルを開くには、OPEN文を使用する。
000410* ファイルのオープン
000420 OPEN OUTPUT 果物ファイル.
オープンモードは、OPEN文の直後に記述する。この場合は、OUTPUTモードなので、ファイルが存在すれば上書きをし、存在しなければ1から作成することを指示している。
ファイルにデータを書き込むには、WRITE文を使用する。
下記は、果物テーブル(1)~果物テーブル(5)までのデータを順次果物レコードに転記し、WRITE文でレコードの内容をファイルに出力している。
000430* 5つの果物データをファイルに書き出し
000440 PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
000450 MOVE 果物テーブル(I) TO 果物レコード
000460 WRITE 果物レコード
000470 END-PERFORM.
MOVE文とWRITE文は次のようにFROM指定を使用して1文にすることもできる。
000460 WRITE 果物レコード FROM 果物テーブル(I)
ここで、1つ注意が必要なのは、索引ファイルは、順呼出し(ACCESS MODE SEQUENTIAL)の場合は、主キーの昇順にデータを 書き出さなければならない点である。ここでは、主キーである商品番号の値は、‘101’, ‘102’, … , ’105’と昇順になっており、WRITE文は成功する。
ファイルを閉じるには、CLOSE文を使用する。
000480* ファイルのクローズ
000490 CLOSE 果物ファイル.
上記のプログラムを実行すると次のようなファイルが作成される。
SQLITE3.exeコマンドで索引ファイル(実際にはSQLITE3データベース)の中身を確認している。(“□”は日本語の空白を示す)
>sqlite3.exe 果物ファイル.sqlite3
sqlite> select * from records;
101|101リンゴ□□□□□□□00010
102|102オレンジ□□□□□00005
103|103メロン□□□□□□□00020
104|104バナナ□□□□□□□00008
105|105イチゴ□□□□□□□00012
sqlite>
なお、SIT COBOLは、OUTPUT指定のOPEN文において、索引ファイルを、次のような規則で作成する。
データベース名 | ASSGIN TOに指定されたファイル名(“果物ファイル.sqlite3”) |
テーブル名 | “records”(固定) |
主キー値を格納するカラム名 | “KEY”(固定) |
レコード内容を格納する領域のカラム名 | “DATA”(固定) |
次に、索引ファイルのレコードを書き換えたり削除したりする例を見ていく。
参照するファイルは、例(1)で作成した”果物ファイル.sqlite3”である。
以下のプログラムは、オレンジ(商品番号102)の数量を15に変更し、またバナナレコード(商品番号104)を削除するプログラムである。
(サンプルプログラム名:索引ファイルの更新例.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE002.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS DYNAMIC.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130 02 商品番号 PIC 9(3).
000140 02 名前 PIC N(10).
000150 02 数量 PIC 9(5).
000160 PROCEDURE DIVISION.
000170 MAIN00.
000180* ファイルのオープン
000190 OPEN I-O 果物ファイル.
000200* 主キー(商品番号)に102を設定してオレンジレコードを読む
000210 MOVE 102 TO 商品番号 OF 果物レコード.
000220 READ 果物ファイル
000230 INVALID
000240 DISPLAY "READ: オレンジレコードが見つからない"
000250 STOP RUN
000260 END-READ.
000270* 数量を15にして更新する。
000280 MOVE 15 TO 数量 OF 果物レコード.
000290 REWRITE 果物レコード
000300 INVALID
000310 DISPLAY "REWRITE: オレンジレコードの更新に失敗"
000320 STOP RUN
000330 END-REWRITE.
000340* 主キー(商品番号)に104を設定してバナナレコードを読む
000350 MOVE 104 TO 商品番号 OF 果物レコード.
000360 DELETE 果物ファイル
000370 INVALID
000380 DISPLAY "DELETE: バナナレコードの削除に失敗"
000390 STOP RUN
000400 END-DELETE.
000410* ファイルのクローズ
000420 CLOSE 果物ファイル.
000430 STOP RUN.
例(1)においては索引ファイルのアクセスモードは、順呼出し(SEQUENTIAL)としたが、キー指定でアクセスできるように、動的呼出し(DYNAMIC)とした。
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS DYNAMIC.
なお、キー指定アクセスのみであれば、アクセスモードは、乱呼出し(RANDOM)でもよいが、動的呼出しにしておくと、順呼出し、乱呼出しの両方が可能となるので、このプログラム例では動的呼出しにしている。
データの入力を行うには、まず主キーである商品番号に値を設定し、それからREAD文を実行する。
以下の例では、商品番号に、オレンジの商品番号である102を設定して、READ文で果物ファイルを読んでいる。
000230行のINVALID指定は、INVALID条件(指定したキーの値を持つレコードが存在しない)が発生したときの処理を書いている。ここでは、DISPLAY文を実行後、プログラムを終了させている。
000200* 主キー(商品番号)に102を設定してオレンジレコードを読む
000210 MOVE 102 TO 商品番号 OF 果物レコード.
000220 READ 果物ファイル
000230 INVALID
000240 DISPLAY "READ: オレンジレコードが見つからない"
000250 STOP RUN
000260 END-READ.
READ文が成功すると、果物レコードには、オレンジのデータが読み込まれているので、数量を15に変更して、REWRITE文を実行する。
000270* 数量を15にして更新する。
000280 MOVE 15 TO 数量 OF 果物レコード.
000290 REWRITE 果物レコード
000300 INVALID
000310 DISPLAY "REWRITE: オレンジレコードの更新に失敗"
000320 STOP RUN
000330 END-REWRITE.
000300行のINVALID指定は、READ文と同じく、INVALID条件が発生したときの処理を書いている。ここでは、DISPLAY文を実行後、プログラムを終了させている。
なお、上記の更新の流れは、READ文でレコードを読み、そのレコードをREWRITE文で更新という流れとしたが、動的呼出し(DYANMIC)の場合は、READ文を実行せずとも、ただちにREWRITE文を実行できる。したがって、レコードの一部の更新だけではなく、ほぼ全体を更新するような場合はREWRITE文のみを使ったほうが効率的である。
データの削除を行う場合は、キーに削除したいレコードの値を指定してDELETE文を実行する。
下記の例では、バナナレコードを削除するので、主キーである商品番号に104を設定してDELETE文を実行している。
000340* 主キー(商品番号)に104を設定してバナナレコードを読む
000350 MOVE 104 TO 商品番号 OF 果物レコード.
000360 DELETE 果物ファイル
000370 INVALID
000380 DISPLAY "DELETE: バナナレコードの削除に失敗"
000390 STOP RUN
000400 END-DELETE.
000370行のINALID指定については、READ文、REWRITE文で説明したとおり、指定したキーが存在しない場合の処理を書いている。
上記のプログラムを実行すると’果物ファイル.sqlite3’の中身は次のようになる。
sqlite> select * from records;
101|101リンゴ□□□□□□□00010
102|102オレンジ□□□□□00015
103|103メロン□□□□□□□00020
105|105イチゴ□□□□□□□00012
sqlite>
オレンジの数量が15に変わっており、またバナナレコードが削除されているのがわかる。
索引ファイルを動的呼出しで開くと、特定のキー値以上のデータだけを読み出すことができる。
例えば、’果物ファイル.sqlite3’の、商品番号が103以上のレコードをすべて読み出すというプログラムは次のようになる。
(サンプルプログラム名:索引ファイルの更新例2.cob)
000000 IDENTIFICATION DIVISION.
000010 PROGRAM-ID. INDFILE003.
000020 ENVIRONMENT DIVISION.
000030 INPUT-OUTPUT SECTION.
000040 FILE-CONTROL.
000050 SELECT 果物ファイル ASSIGN TO "./果物ファイル.sqlite3"
000060 ORGANIZATION IS INDEXED
000070 RECORD KEY IS 商品番号 OF 果物レコード
000080 ACCESS MODE IS DYNAMIC.
000090 DATA DIVISION.
000100 FILE SECTION.
000110 FD 果物ファイル.
000120 01 果物レコード.
000130 02 商品番号 PIC X(3).
000140 02 名前 PIC N(10).
000150 02 数量 PIC 9(5).
000160 PROCEDURE DIVISION.
000170 MAIN00.
000180* ファイルのオープン
000190 OPEN I-O 果物ファイル.
000200* 主キー(商品番号)に103を指定してSTART文を実行する
000210 MOVE 103 TO 商品番号 OF 果物ファイル.
000220 START 果物ファイル
000230 INVALID
000240 DISPLAY "START: レコードが見つからない"
000250 STOP RUN
000260 END-START.
000270 PERFORM FOREVER
000280 READ 果物ファイル NEXT
000290 AT END
000300 EXIT PERFORM
000310 END-READ
000320 DISPLAY 果物レコード
000330 END-PERFORM.
000340* ファイルのクローズ
000350 CLOSE 果物ファイル.
000360 STOP RUN.
今回は、更新を伴なわない例であるが、ひとまず、I-Oモードで開いておく。
000180* ファイルのオープン
000190 OPEN I-O 果物ファイル.
主キーのある特定の値以上のレコードを順次読み出しするには、START文を使用する。
このプログラムでは、次のように主キーである商品番号に103を指定してSTART文を実行している。
000200* 主キー(商品番号)に103を指定してSTART文を実行する
000210 MOVE 103 TO 商品番号 OF 果物ファイル.
000220 START 果物ファイル
000230 INVALID
000240 DISPLAY "START: レコードが見つからない"
000250 STOP RUN
000260 END-START.
このSTART文を実行してから READ NEXT文を実行すると、最初に103の主キーを持つレコードが読み出される。
しかし、主キーに103を持つレコードが存在しない場合は、INVALID条件が発生し、000230行目から始まるDISPLAY文とSTOP文が実行される。
実は、上記のSTART文は次のような書き方と同じである。
000210 MOVE 103 TO 商品番号 OF 果物ファイル.
000220 START 果物ファイル KEY = 商品番号 OF 果物ファイル
そして、指定したキーを持つレコードが存在しなくとも、それ以上の値を持つレコードが存在した場合は、INVALID条件としないようにもできる。それは、次のようにキー指定に”>=“を書く。
000210 MOVE 104 TO 商品番号 OF 果物ファイル.
000220 START 果物ファイル KEY >= 商品番号 OF 果物ファイル
商品番号104はバナナレコードであるが、例(2)にて削除しているため、現時点でレコードは存在しない。しかし、商品番号105を持つイチゴレコードが存在するので、このSTART文はINVALID条件は発生せず成功する。そして、次に実行するREAD NEXT文では、商品番号105のイチゴレコードが読み込まれる。
なお、「KEY > 商品番号 OF 果物ファイル」と書くと、今設定されている商品番号よりも大きい商品番号を持つレコードに位置づく。
START文で位置づけたレコードの読み込みは、READ
NEXT文によって行う。
このプログラムでは、FOREVER指定のPERFORMで、EOFとなるまでREAD
NEXTを実行している。
000270 PERFORM FOREVER
000280 READ 果物ファイル NEXT
000290 AT END
000300 EXIT PERFORM
000310 END-READ
000320 DISPLAY 果物レコード
000330 END-PERFORM.
ここで、“NEXT”は必須であることに注意されたい。もし、NEXTを省略した場合には、START命令で位置づいたレコードではなく、新たに主キーの値を持つレコードを読込むという指定となるからである。
上記のプログラムを実行すると、00320行目のDISPLAY文により下記が出力される。(“□”は日本語の空白を示す)
103メロン□□□□□□□□□□00020
105イチゴ□□□□□□□□□□00012
START文によって、最初に商品番号が103を持つレコードに位置づけられ、その後、READ NEXT文によって、103および105のレコードが読込まれたことがわかる。
ここでは、早見表として、ファイル関連の文法についてまとめておく。
SELECT句は、ファイル形式の定義を行う。環境部(ENVIRONMENT部)の入出力節(INPUT-OUTPUT節)のファイル管理段落(FILE-CONTROL段落)に記述する。
SELECT ファイル名-1 ASSIGN TO { 定数-1 | 一意名-1 }
[[ORGANIZATION IS] SEQUENTIAL]
[ACCESS MODE IS SEQUENTIAL]
[FILE STATUS IS 一意名-2].
SELECT ファイル名-1 ASSIGN TO { 定数-1 | 一意名-1 }
[ORGANIZATION IS] INDEXED
ACCESS MODE IS {SEQUENTIAL | RANDOM | DYNAMIC}
RECORD KEY IS データ名-1
[ALTERNATE RECORD KEY IS {データ名-2} ... ]
[FILE STATUS IS 一意名-2].
FD句は、ファイルのデータ構造の定義であり、データ部(DATA部)のファイル節(FILE節)に指定する。
FD ファイル名-1.
{ レベル番号 データ定義 } ...
CLOSE文は、ファイルを閉じる
CLOSE {ファイル名-1} ...
DELETE文はレコードを削除する。
DELETE ファイル名-1
DELETE ファイル名-1
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-DELETE]
ファイルを開く
OPEN {{INPUT | OUTPUT | I-O | EXETND} ファイル名-1 ...} ...
ファイルからレコードを読み込む
READ ファイル名-1 [NEXT] [INTO 一意名-1]
[AT END 無条件文-1]
[NOT AT END 無条件文-2]
[END-READ]
READ ファイル名-1 [INTO 一意名-1]
[KEY IS データ名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-READ]
レコードを更新する。
REWRITE レコード名-1 [FROM 一意名-1]
[END-REWRITE]
REWRITE レコード名-1 [FROM 一意名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-1]
[END-REWRITE]
指定したキーを持つレコードに位置づける
START ファイル名
[KEY {= | > | >=} データ名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-START]
レコードを書き出す
WRITE レコード名-1 [FROM 一意名-1]
[END-WRITE]
WRITE レコード名-1 [FROM 一意名-1]
[INVALID 無条件文-1]
[NOT INVALID 無条件文-2]
[END-WRITE]
ファイルの入出力状態が成功以外のときに実行される手続きを宣言する。
USE AFTER STANDARD {EXCEPTION | ERROR} PROCEDURE ON
{ {ファイル名-1}... | INPUT | OUTPUT | I-O | EXTEND}