1人COBOL再研修〜テーブル編〜

[これ](https://qiita.com/zama_8722/items/e59f2f62aa921407b442)の続き。いよいよ最終回。更新ペースが遅いからとても長く感じた。

最後はテーブルについて学習しようと思う。

## テーブルについて

考え方は他言語で言う配列に近い。これまでの学習内容だと、同じデータが何件もあるとき、一個一個定義していかなければならなかった。

例えばテーブルを使わないで3個分のデータ項目を作成するとしたら、こうなる。

```:3個分のデータ（テーブル未使用）
      *---1---------2---------3---------4---------5-----
       01  DATA.
         03  DATA1            PIC X(10).
         03  DATA2            PIC X(10).
         03  DATA3            PIC X(10).
```

これが何個持ってなるとやってらんない。

そこでテーブルが出てくる。

## 構文・使い方

```:構文
レベル番号(親)  テーブル名.
  レベル番号(子)  項目名            PIC 型(文字数)  OCCURES 要素数.
```

テーブルを定義する際は、データ項目定義時に、`OCCURES`句使用し、後ろに作成するテーブル数を指定する。

テーブルを使用すれば、最初の例は次のようになる。

```:3個分のデータ（テーブル使用）
      *---1---------2---------3---------4---------5-----
       01  TABLE.
         03  DATA             PIC X(10) OCCURES 3.
```

これなら大量件数でも対応できる。また、多次元配列のようにしたいときは次のようにすれば良い。

__テーブルレイアウト（テーブル名：`PROFILE-TBL`）__

|項目1|項目2|項目3|
|:---:|:---:|:---:|
|`DT-NO PIC 9(01)`|`NICNAME PIC X(10)`|`COMMENT X(20)`|
|データ番号|ニックネーム|コメント|

> ※ 項目1〜項目3の1セットは`PROFILE`とする

```:PROFILE-TBL
      *---1---------2---------3---------4---------5-----
       01  PROFILE-TBL.
         03  PROFILE          OCCURS 3.
           05  DT-NO          PIC 9(01).
           05  NICNAME        PIC X(10).
           05  COMMENT        PIC X(20).
```

上記の構成イメージはこんな感じ。

![FIG1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163288/c9a10746-9ca1-bc37-5718-7d6b796d7f88.png)

### データ項目にアクセスする

上の図を見ての通り、`OCCURES`句を使用してテーブルを作成すると、同じ項目名が指定した数分できるため、今までのやり方ではアクセスできない。アクセスするには、アクセスしたい添字番号を指定する必要がある。指定するには、アクセスしたい項目名の後ろにカッコでアクセスしたい添字番号を記載する。

例えば、2番目の`PROFILE`の`NICNAME`を`'ZAMA8722'`としたい場合は以下のようになる。


```:代入例
MOVE  'ZAMA8722'  TO  NICNAME(2).
```

COBOLは添字番号が__1から__なので、多言語で0からで慣れている場合は注意が必要。

#### 1番上から総なめするときは

`PERFORM VARYING`でできる。例えば、上で作成したテーブルの全項目にデータが入っていて、全て画面出力したいときは、次のようにしてあげる。

```:ループによる総なめ
      *---1---------2---------3---------4---------5-----
         PERFORM
           VARYING            IDX FROM 1 BY 1
           UNTIL              IDX > 3
            DISPLAY           PROFILE(IDX)
         END-PERFORM.
```
※`IDX`は`9(01)`型の添字

## 外部データをテーブルに入れる

読み込んだレコードをそのまま`MOVE`すればOK

```:サンプル
      *---1---------2---------3---------4---------5-----
       IDENTIFICATION         DIVISION.
       PROGRAM-ID.            SAMPLE.
      *
       ENVIRONMENT            DIVISION.
       INPUT-OUTPUT           SECTION.
       FILE-CONTROL.
         SELECT  IN-FILE      ASSIGN 'infile.dat'
                              ORGANIZATION LINE SEQUENTIAL.
      *
       DATA                   DIVISION.
       FILE                   SECTION.
       FD  IN-FILE            LABEL RECORD STANDARD
                              BLOCK CONTAINS 0 RECORDS.
       01  IN-REC             PIC X(31).
      *
       WORKING-STORAGE        SECTION.
       01  PROFILE-TBL.
         03  PROFILE          OCCURS 3.
           05  DT-NO          PIC 9(01).
           05  NICNAME        PIC X(10).
           05  COMMENT        PIC X(20).
       01  IDX                PIC 9(01).
       01  FLG                PIC X(01).
      *
       PROCEDURE              DIVISION.
       PGM-FLOW               SECTION.
      *-- PGM-FLOW SEC
       PGM-FLOW-S.
         OPEN                 INPUT  IN-FILE.
         MOVE                 SPACE  TO  FLG.
         MOVE                 ZERO   TO  IDX.
         PERFORM              PGM-READ.
         PERFORM              PGM-MAIN
           UNTIL              FLG = '1'.
         CLOSE                IN-FILE.
       PGM-FLOW-E.
         STOP RUN.
      *-- PGM-READ SEC
       PGM-READ               SECTION.
       PGM-READ-S.
         READ                 IN-FILE
           AT END
             MOVE             '1'  TO  FLG
           NOT AT END
             COMPUTE          IDX = IDX + 1
         END-READ.
       PGM-READ-E.
         EXIT.
      *-- PGM-MAIN SEC
       PGM-MAIN               SECTION.
       PGM-MAIN-S.
         MOVE                 IN-REC  TO  PROFILE(IDX).
         PERFORM              PGM-READ.
       PGM-MAIN-E.
         EXIT.
```

```:infile.dat
1COBOLER001TABLE SAMPLE
2ALICE     HELLO EVERYONE
3BOB-001   NICE TO MEET YOU
```

## テーブルの再定義

再定義をすることで、あるデータ項目を別のレイアウトで参照できるようにすることができる。例えば、

```
      *---1---------2---------3---------4---------5-----
       01  MEMBER-LIST
         03  FILLER           PIC X(31) VALUE 
             '1COBOLER001TABLE SAMPLE        '.
         03  FILLER           PIC X(31) VALUE
             '2ALICE     HELLO EVERYONE      '.
         03  FILLER           PIC X(31) VALUE
             '3BOB-001   NICE TO MEET YOU    '.
```
のようなデータがあり、これを上でも使用したテーブルのレイアウトで使用したいときは、`REDEFINES`句を使用して再定義する。

```:構文
レベル番号(親)  テーブル名  REDEFINES  再定義するデータ項目.
  レベル番号(子)  項目名            PIC 型(文字数)  OCCURES 要素数.
```

とりあえずサンプルプログラム。

```:サンプル
      *---1---------2---------3---------4---------5-----
       IDENTIFICATION         DIVISION.
       PROGRAM-ID.            SAMPLE.
      *
       ENVIRONMENT            DIVISION.
      *
       DATA                   DIVISION.
       WORKING-STORAGE        SECTION.
       01  MEMBER-LIST.
         03  FILLER           PIC X(31) VALUE
             '1COBOLER001TABLE SAMPLE        '.
         03  FILLER           PIC X(31) VALUE
             '2ALICE     HELLO EVERYONE      '.
         03  FILLER           PIC X(31) VALUE
             '3BOB-001   NICE TO MEET YOU    '.
       01  PROFILE-TBL        REDEFINES  MEMBER-LIST.
         03  PROFILE          OCCURS 3.
           05  DT-NO          PIC 9(01).
           05  NICNAME        PIC X(10).
           05  COMMENT        PIC X(20).
       01  IDX                PIC 9(01).
      *
       PROCEDURE              DIVISION.
       PGM-MAIN               SECTION.
       PGM-MAIN-S.
         PERFORM
           VARYING            IDX  FROM 1 BY 1
           UNTIL              IDX > 3
             DISPLAY          NICNAME(IDX)
         END-PERFORM.
       PGM-MAIN-E.
         STOP RUN.
```

```:実行結果
COBOLER001
ALICE
BOB-001
```

このように、固定長のレコードであれば、再定義してデータを別レイアウトで作成し直すことができる。今回の場合は以下のような感じ。

![FIG2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163288/2d9fc852-439d-b14c-b5ef-bc260d4a6c7a.png)

今回はテーブルの学習で再定義を記載したが、別に普通のデータ項目でも使える。また、再定義前のデータ項目の内容を変えれば、再定義後のデータも変更される。

## これにて終了

とりあえずこれでさらっと研修の教本を流すことができた。研修時間外にこうやって復習することで、更に覚えることができたし、合間にググったりすることで、新たな知識も手に入れることができた。

これから配属されて、毎回教本を持ち運ぶわけには行かないので、通勤時間などを使って、もう一度自分が作った記事を見直して行きたいと思う。

## 謝辞

ここまで閲覧頂いた方と、指摘等コメントをしていただいた皆さん、ありがとうございました。