IBM i Db2 for iで処理されたレコードのログ（ジャーナル）を調べたい

上記のご質問をいただきまして、背景として
ある処理中のエラーが発生した。その原因を調査するためにエラー発生時点でどのテーブル（物理ファイル）が処理中だったか、どのプログラムからどんな処理を実行中だったかを調べたい、というものでした。

## Db2 for i のテーブル更新ログはジャーナルに書き出される
全体図は下記になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/2d294015-cee6-dc7f-b979-df85cf75b19a.png)

### Db2 for i のテーブルはかつてはジャーナル（ログ）取得しないがデフォだった。
1980年代、ディスクは超高価でしたので本番システムでも200MB（TBじゃないですよw）とかざらな時代だったしデータ更新もCOBOL, RPGでネイティブI/OというSQLでない方式だったためジャーナル取得はオプション扱いでした。現在はSQLでCREATE TABLEするとDb2 for iでもジャーナル(ログ)が自動的に開始・取得されますが、昔からあるテーブルなどはジャーナルが未取得になってたりします。

### ジャーナル取ってる？の確認

    DSPFD FILE(DEMOLIB/TOKMASP2)
        

上記コマンドでDEMOLIBのTOKMASP2のテーブルの状況を確認できます。以下のようにジャーナルイメージに*AFTER または *BOTHが入っていればジャーナル取得設定済みです。
ちなみに*AFTERはレコード更新モードの場合更新後イメージのみ取得する、*BOTHは更新前後で合計2件ログ取得するモードです。ストレージ容量その他から必要性検討して設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/f72f3f32-fedc-8e4d-0d12-a01043027566.png)

### もしジャーナル取得されてない場合は、

    STRJRNPF FILE(DEMOLIB/TOKMASP2) JRN(DEMOLIB/JRN01)  

のように実行するとJRN01というジャーナルにログが取得されます。JRN01というジャーナルが存在していない場合は、上記コマンドの前に下記2つのコマンドを実行してジャーナル（ログ）を取得できる準備をします。
ジャーナルを保管するジャーナルレシーバーを作成

    CRTJRNRCV JRNRCV(DEMOLIB/JRNRCV01)

DB更新時にジャーナルを取得して、ジャーナルレシーバーに格納してくれるジャーナルを作成

    CRTJRN JRN(DEMOLIB/JRN01) JRNRCV(DEMOLIB/JRNRCV01) 

以上でTOKMASP2の更新ログはジャーナルJRN01を通じて確認することができます。（ジャーナルレシーバーはジャーナルの件数が増えると自動的に次のジャーナルを新規作成、切り替わっていきます）

それではジャーナルでDb2 for i の更新情報を確認します。方法は大きく２種類あります。（5250から、SQLから）

## ジャーナルの確認方法：5250を使う方法
ジャーナルの名前、確認したいテーブルのジャーナルを取得しているジャーナルの名前を指定して、下記コマンドを実行します。

```
   DSPJRN DEMOLIB/JRN01
```

と実行すると下記のような画面が表示されます。
コード　と　タイプ　というカラムがREAD/ADD/DELETEなどDBに対する処理パターンを表します。

下記で順序179の行は R UP で、レコードをREADしUPDATEした後のジャーナル（ログ）であることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/220ea3fb-12f8-8b3a-0bee-7e469717ad34.png)

オプションに5を入力、エンターキーすると更新されたレコードの内容が表示されます。実際に更新されたレコード内のパックフィールドやDBCSが文字化けしてしまいますが、冒頭に 01010 アイリョカン　などどのレコードかは確認ができます。
PF11キーを押すとHEXで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/a07b07ff-8b34-8145-3b51-0dcbc5f2221f.png)


コード、タイプの説明は下記マニュアルを参照してください。
https://www.ibm.com/docs/ja/i/7.3?topic=information-all-journal-entries-by-code-type

＊プログラムでジャーナルの各レコードを取得して処理したい場合は、RTVJRNEコマンドを使用します。

## SQLを使う方法: IBM i サービスDISPLAY_JORNALテーブル関数

割と近年追加になった機能でIBM i 7.2以降で利用可能です。
DISPLAY_JOURNAL テーブル関数　をSQLから実行してジャーナルを検索できます。

```
 SELECT *FROM TABLE (QSYS2.DISPLAY_JOURNAL( 'DEMOLIB', 'JRN01'))
```

のように実行します。
**＊ACSのSQLスクリプト実行画面などではコマンドの末尾にセパレーターの意味の ; セミコロンを付けてください。** (以下の２つ目のサンプル以降はセミコロン付きです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/88414a10-b151-5268-2769-fbddb76b9a96.png)


### 例：TOKMASP2に対して、ユーザーQSECOFRが実行したすべての変更をリストする。

```
    SELECT journal_code, journal_entry_type, object, object_type, X.* 
    FROM TABLE (
      QSYS2.Display_Journal(
            'DEMOLIB', 'JRN01', -- ジャーナル名
            OBJECT_LIBRARY=>'DEMOLIB', OBJECT_NAME=>'TOKMASP2',
            OBJECT_OBJTYPE=>'*FILE', OBJECT_MEMBER=>'TOKMASP2' 
    ) ) AS X
    WHERE journal_entry_type in ('DL', 'PT', 'PX', 'UP') AND "CURRENT_USER" = 'QSECOFR'
    ORDER BY entry_timestamp DESC;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/61a343f8-2349-e4e5-38a0-6ec4b9eaf6f4.png)


### 例：現行ジャーナルID(JID)で、TOKMASP2の過去１時間の更新処理をリストする。なお、D　データベース・ファイル操作　F　データベース・ファイル・メンバー操作　R　特定レコードの操作 

```
    SELECT journal_code, journal_entry_type, object, object_type, X.* 
      FROM TABLE (QSYS2.Display_Journal('DEMOLIB', 'JRN01', 
            JOURNAL_CODES => 'D,F,R',
            STARTING_RECEIVER_NAME => '*CURCHAIN',                         
            OBJECT_OBJTYPE=>'*FILE',
            OBJECT_LIBRARY=>'DEMOLIB', 
            OBJECT_NAME=>'TOKMASP2',
            OBJECT_MEMBER=>'*ALL'
    ) ) AS X 
      WHERE entry_timestamp > CURRENT TIMESTAMP - 1 HOUR  
      ORDER BY entry_timestamp DESC  ;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/0bcf9a99-74ae-c974-50e5-26da384d725d.png)

### 例）ジャーナルIDが現行以外も含めてTOKMASP2の過去1時間以内のすべての更新をリストする

```
    SELECT journal_code, journal_entry_type, hex( journal_identifier ), 
        object, object_type, X.* 
      FROM TABLE (QSYS2.Display_Journal('DEMOLIB', 'JRN01', 
            JOURNAL_CODES => 'D,F,R',
            STARTING_RECEIVER_NAME => '*CURCHAIN'                         
    ) ) AS X 
      WHERE LEFT(OBJECT,20) = CHAR('TOKMASP2', 10) CONCAT CHAR('DEMOLIB', 10)
      and entry_timestamp > CURRENT TIMESTAMP - 1 HOUR
      ORDER BY entry_timestamp DESC  ;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/48f40f32-95cf-7a51-923b-01f7e417f758.png)


### 参考マニュアルページ：
IBM i 7.5 https://www.ibm.com/docs/ja/i/7.5?topic=services-display-journal-table-function