内部テーブルの照会(READ、SORT、DESCRIBE)
15.5 内部テーブルの照会(READ、SORT、DESCRIBE)
ここでは、内部テーブルの照会方法として以下を説明します。
内部テーブルを操作する方法として、下記の3つがあります。
・READ
・SORT
・DESCRIBE
READ
READ TABLE命令による内部テーブルの読み込み処理について解説します。
READ TABLE命令は、内部テーブルの単一行を抽出する命令です。
主にREAD TABLE命令の場合は、内部テーブルのレコードを抽出する場合に用います。
READ TABLE命令は指定した内部テーブルから単一行を読み込み、指定した構造に格納します。
読み込むレコードは、WITH KEYオプションで指定します。
例えば「WITH KEY VBELN = ‘100000000’」 とすれば、受注伝票 100000000のレコード(行)が対象となります。
もし、読み込む行が一意にならない場合は、最初に一致するレコードが読み込み対象となります。
したがって、キーの指定が不十分な場合(レコードを一意に特定できない場合)には、意図したものと
違うレコードが抽出されてしまいます。
基本は、レコードを一意に指定できるようにKEYを指定しましょう。
あまり使用されませんがINDEXオプションにて、行番号を指定することも可能です。
READ TABLE命令のイメージ
「サンプルコード」①
REPORT Z_SAMPLE155.
*型定義
TYPES:
BEGIN OF TY_RECORD,
COLP TYPE I,
COLQ TYPE I,
END OF TY_RECORD.
*変数定義
DATA:
LT_MYTABLE TYPE STANDARD TABLE OF TYP_RECORD,
LS_RECORD TYPE TYP_RECORD.
*主処理
START-OF-SELECTION.
"内部テーブル作成(6行)
DO 6 TIMES.
LS_RECORD-COLP = SY-INDEX.
LS_RECORD-COLQ = SY-INDEX + 5.
APPEND LS_RECORD TO LT_MYTABLE.
ENDDO.
*READ命令(単一行を抽出)
READ TABLE LT_MYTABLE INTO LS_RECORD WITH KEY COLQ = 8.
*抽出できなかった場合、処理終了
IF SY-SUBRC <> 0.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
*出力
WRITE: / LS_RECORD-COLP, LS_RECORD-COLQ.
END-OF-SELECTION.
このサンプルでは、DO ループで6行の内部テーブルを作り、COLQ = 8 の行を READ TABLEで1行取り出します。
READの成否は SY-SUBRCで判定し、見つからない場合はエラーメッセージで終了します。
また、DOの繰り返し回数を示す SY-INDEX を使って値を作っています。
実行結果
補足(SY-INDEXについて)
先述の通り、SY-INDEXは、現在のループパス件数が格納されるシステム変数です。
詳しくは20章で学習しますので、今回は簡単に解説します。
SY-INDEXは データ型が 「INT4」なので数値が格納されます。
「DO 6 TIMES」で6回繰り返しなさい、という命令なので、
COLPには1、2、3、4、5、6が格納されます。
COLQには5加算された、6、7、8、9、10、11が格納されます。
補足(SY-SUBRCについて)
SY-SUBRCもシステム変数の1つです。
詳しくは20章で学ぶため、
当章ではABAP命令が失敗すると「0以外の数字」が格納される変数、と理解しましょう。
IF SY-SUBRC <> 0.
<処理>
ENDIF.
上記のように記述すると、直前の処理が失敗したら<処理> を実行する、という意味になります。
また、MESSAGE E019(ZTEST2021)は、
エラーメッセージを出力して処理を終了する、という命令です。
詳しくは18章で学習するため、プログラムの流れが理解できればOKです。
デバッグ機能を利用し、READ TABLE命令実行時の値を確認
READ(新構文)
S/4 HANA化に伴い、READ命令の記述方法が変更され、より便利に扱えるようになりました。
従来までの記述方法と大きく変わりますが、動作としては基本的に同じです。
ただし、旧構文では内部テーブルの単一行を抽出していましたが
新構文では単一行の抽出に加えて、抽出した行の項目(列)も指定することができるようになりました。
実務ではどちらも用いられるため、旧構文と新構文の違いを理解して
柔軟に対応できるようにしましょう。
構文は以下の通りです。
項目は、「-(ハイフン)」で指定します。
「サンプルコード」②
REPORT Z_SAMPLE155_MODIFY.
*型定義
TYPES:
BEGIN OF TY_RECORD,
COLP TYPE I,
COLQ TYPE I,
END OF TY_RECORD.
*変数定義
DATA:
LT_MYTABLE TYPE STANDARD TABLE OF TYP_RECORD,
LS_RECORD TYPE TY_RECORD.
*主処理
START-OF-SELECTION.
*内部テーブル作成
DO 6 TIMES.
LS_RECORD-COLP = SY-INDEX.
LS_RECORD-COLQ = SY-INDEX + 5.
APPEND LS_RECORD TO LT_MYTABLE.
ENDDO.
*READ命令(単一行を抽出)
TRY.
LS_RECORD = LT_MYTABLE[ COLQ = 8 ].
*抽出できなかった場合、処理終了
CATCH CX_SY_ITAB_LINE_NOT_FOUND.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDTRY.
*出力
WRITE: / LS_RECORD-COLP,LS_RECORD-COLQ.
END-OF-SELECTION.
実行結果
実行結果は同じになります。
補足(TRY~ENDTRYについて)
新構文にてデータが読み込めない場合、ショートダンプが発生します。ショートダンプを防ぐためのコードが以下です。
TRY. < READ(新構文) > CATCH CX_SY_ITAB_LINE_NOT_FOUND. < 存在しない場合の処理 > ENDTRY.
例外処理と呼ばれますが、今はREAD命令時にショートダンプを防ぐものだと理解できればOKです。
また、ショートダンプを防ぐための記述方法がいくつかあるため、紹介します。
詳しく理解しようとせず、色々な記述方法があると認識できれば良いでしょう。
「サンプルコード」③
REPORT Z_SAMPLE155_LINEEXISTS.
~割愛~
*READ命令(単一行を抽出)
IF LINE_EXISTS( IT_MYTABLE[ COLQ = 8 ] ).
ST_RECORD = IT_MYTABLE[ COLQ = 8 ].
*抽出できなかった場合、処理終了
ELSE.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
~割愛~
補足(LINE_EXISTSについて)
LINE_EXISTSは条件式(IF文)で用いられます。 詳しくは19章で学習するため、括弧内のデータが存在するかチェックする命令という点を確認しておきます。
IF LINE_EXISTS( < READ(新構文) > ). ← 存在チェック(LINE_EXISTS命令) < READ(新構文) > ← 単一行/項目を取得(READ命令) ELSE. <存在しない場合の処理> ← エラー処理(存在しない場合の処理) ENDIF.
事前に抽出データが存在するかを確認して、存在していればREAD(抽出)し、在しなければ
<存在しない場合の処理>を実行するというコードになります。
データが存在する場合のみREADするため、ショートダンプを防ぎます。
「サンプルコード」④
REPORT Z_SAMPLE155_OPTIONAL.
~割愛~
*READ命令(単一行を抽出)
LS_RECORD = VALUE #( LT_MYTABLE[ COLQ = 8 ] OPTIONAL ).
*抽出できなかった場合、処理終了
IF LS_RECORD IS INITIAL.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
~割愛~
補足(OPTIONALについて)
OPTIONALはVALUE命令と組み合わせて使用します。
OPTIONALを指定した場合は、データが読み込めない場合でもショートダンプが発生しません。
また、<構造 | 変数>には初期値が設定されます。
補足(INITIALについて)
INITIALは条件式(IF文)で用いられます。 詳しくは19章で学習するため、初期値かどうかチェックする命令だと理解できればOKです。
IF ST_RECORD IS INITIAL. < 処理 > ENDIF.
ST_RECORDが初期値の場合、<処理>を実行するというコードになります。
「サンプルコード」➄
REPORT Z_SAMPLE155_NEW.
*型定義
TYPES:
BEGIN OF TY_RECORD,
COLP TYPE I,
COLQ TYPE I,
END OF TY_RECORD.
*変数定義
DATA:
LT_MYTABLE TYPE STANDARD TABLE OF TY_RECORD,
LS_RECORD TYPE TY_RECORD.
*主処理
START-OF-SELECTION.
*内部テーブル作成
DO 6 TIMES.
LS_RECORD-COLP = SY-INDEX.
LS_RECORD-COLQ = SY-INDEX + 5.
APPEND LS_RECORD TO LT_MYTABLE.
ENDDO.
*READ命令(単一行を抽出)
TRY.
DATA(WK_COLQ) = LT_MYTABLE[ COLQ = 8 ]-COLQ .
*抽出できなかった場合、処理終了
CATCH CX_SY_ITAB_LINE_NOT_FOUND.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDTRY.
*出力
WRITE: / ‘WK_COLQ =’,WK_COLQ.
END-OF-SELECTION.
実行結果
項目を指定することも可能です。
SORT
内部テーブルを昇順・降順に並び替えるSORT命令について解説します。
SORT命令は並び替え(ソートの優先順や、昇順・降順の混合など)を行う命令です。
SORT命令の処理は、キーによって内部テーブルのレコードをソートします。
この命令では、明示的なソートキーを指定せず、内部テーブルをソートします。
明示的なソートキーを 指定しないと、内部テーブルはテーブルキーに従ってソートされます。
オプションASCENDING(昇順)または DESCENDING(降順)を使用して、ソート順を明示的に指定することができます。
指定しない場合、デフォルトで昇順にソートされます。
・ASCENDING ⇒ 昇順(省略時デフォルト)
・DESCENDING ⇒ 降順
昇順ソートの例
内部テーブル:LT_TABのテーブルキーがNUMBERの場合、
SORT LT_TAB.
と記述とすれば、図のようにレコードが並び変えられます。
SORT命令は、キー項目であるNUMBER項目を優先してソートします。
キーは、内部テーブルの宣言時に指定しているものや、標準テーブルのキー項目を参照している項目が
該当します。
また、ASCENDING / DESCENDINGオプションを指定していないため、デフォルトで昇順に
並び替えされています。
つまり、「SORT」だけ記載した場合でも、昇順ソートを明示的に指定した、
SORT LT_TAB ASCENDING.
と同じ意味になります。
ASCENDINGオプションはデフォルトなので、指定する必要性はありませんが、ソースコードの可読性向上を目的として明示する場合があります。
降順ソートの例
内部テーブル:ITAB1のキー項目がNUMBERの場合、
SORT LT_TAB DESCENDING.
と記述した場合、NUMBERをキーに降順に並び替えされます。
SORT BY
どの項目で、昇順/降順のどちらで並び替えるかを明示できます。 明示的なソートキーを指定し、内部テーブルを昇順・降順に並び替えるSORT BY命令について解説します。
内部テーブルを、明示的に指定した項目をソートキーとして並び替えます。
ソートキーは複数指定することができますが、複数項目を指定した場合は、左から順に優先順位が高いキーとして扱われます。
オプションASCENDING(昇順)または DESCENDING(降順)を使用することで、ソート順を明示的に指定することができます。
指定しない場合、デフォルトで昇順にソートされます。
・ASCENDING ⇒ 昇順(デフォルト)
・DESCENDING ⇒ 降順
「サンプルコード」①
REPORT Z_SAMPLE156.
*主処理
START-OF-SELECTION.
*データ抽出
SELECT FROM ZTEST_TBL_001
FIELDS CLASS, “組
NUM, “出席番号
LASTNAME, “姓
FIRSTNAME “名
INTO TABLE @DATA(LT_STUDENTS).
*抽出できなかった場合、処理終了
IF SY-SUBRC <> 0.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
*ソート
SORT LT_STUDENTS BY NUM ASCENDING. "出席番号(昇順)
*抽出結果を出力
WRITE: / '組',
15 '出席番号',
30 '姓',
45 '名'.
LOOP AT LT_STUDENTS INTO DATA(LS_STUDENTS).
WRITE: / LS_STUDENTS-CLASS, "組
15 LS_STUDENTS-NUM, "出席番号
30 LS_STUDENTS-LASTNAME, "姓
45 LS_STUDENTS-FIRSTNAME. "名
ENDLOOP.
END-OF-SELECTION.
実行結果
■デバッグ機能を利用し、SORT BY ASCENDING命令実行時の値を確認
項目:NUM(出席番号)の昇順でソートされていることが確認できます。
「サンプルコード」②
REPORT Z_SAMPLE156_MODIFY.
*主処理
START-OF-SELECTION.
*データ抽出
SELECT FROM ZTEST_TBL_001
FIELDS CLASS, "組
NUM, "出席番号
LASTNAME, "姓
FIRSTNAME "名
INTO TABLE @DATA(LT_STUDENTS).
*抽出できなかった場合、処理終了
IF SY-SUBRC <> 0.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
*ソート
SORT LT_STUDENTS BY CLASS DESCENDING "組 (降順)
NUM DESCENDING."出席番号(降順)
*抽出結果を出力
WRITE: / '組',
15 '出席番号',
30 '姓',
45 '名'.
LOOP AT LT_STUDENTS INTO DATA(LS_STUDENTS).
WRITE: / LS_STUDENTS-CLASS, "組
15 LS_STUDENTS-NUM, "出席番号
30 LS_STUDENTS-LASTNAME, "姓
45 LS_STUDENTS-FIRSTNAME. "名
ENDLOOP.
END-OF-SELECTION.
実行結果
■デバッグ機能を利用し、SORT BY DESCENDING 命令実行時の値を確認
項目:CLASS(組)の降順(優先順位1位)
項目:NUM(出席番号)の降順(優先順位2位)
でソートされていることが確認できます。
前述の通り、2項目以上ソートする場合は、指定した項目の順でソートされます。 また、昇順と降順を組み合わせてソートすることも可能です。
DESCRIBE
ABAPにおける内部テーブルの属性を読み込む命令「DESCRIBE TABLE」について解説します。
DESCRIBE TABLE命令は、指定した内部テーブルの属性を読み取る命令です。
読み取りたい内部テーブルの属性に応じてオプションがあり、オプションなしではDESCRIBE TABLE命令を利用することはできません。
必ず、いずれかのオプションを指定する必要があります。
DESCRIBE TABLE命令には2つのオプションがあります。
・LINES:内部テーブルの行数を取得
・KIND:内部テーブルのテーブルタイプ(標準/ソート/ハッシュ)を取得
DESCRIBE LINES
ABAPにおける内部テーブルの属性を読み込む命令「DESCRIBE TABLE」で、
LINESオプションを利用すると、内部テーブルの行数を判別することができます。
判別した行数については、LINESオプションの後に指定した変数に格納されます。
LINESオプションの後に指定する変数には、整数しか入りません。
データ型は「I(整数)」でなければなりません。
DESCRIBE LINESの例
DESCRIBE TABLE LT_TAB LINES TAB_CNT.
と記述すると、
内部テーブル「LT_TAB」の内容が以下の場合、変数「TAB_CNT」には「9」が格納されます。
DESCRIBE KIND
KINDオプションは、指定した内部テーブルのテーブルタイプを判別することができます。
KINDオプションの後に指定した変数には、テーブルタイプに応じて
以下のいずれかの文字が格納されます。
・標準テーブルの場合「T」
・ソートテーブルの場合「S」
・ハッシュテーブルの場合「H」
「サンプルコード」①
REPORT Z_SAMPLE157.
*主処理
START-OF-SELECTION.
*データ抽出
SELECT FROM ZTEST_TBL_001
FIELDS *
INTO TABLE @DATA(IT_STUDENTS).
*抽出できなかった場合、処理終了
IF SY-SUBRC <> 0.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
*内部テーブルの行数を取得
DESCRIBE TABLE IT_STUDENTS LINES DATA(WK_LINES).
*内部テーブルのテーブルタイプを取得
DESCRIBE TABLE IT_STUDENTS KIND DATA(WK_KIND).
*出力
WRITE: '<内部テーブル:IT_STUDENTS>',
/ '行数',WK_LINES,
/ 'テーブルタイプ',WK_KIND.
デバッグ機能を利用し、 DESCRIBE TABLE 命令実行時の値を確認\
内部テーブル:IT_STUDENTSは6行あります。
よって、DESCRIBE TABLE LINES命令により、内部テーブルの行数を取得すると、
変数:WK_LINESには6が入ります。
また、内部テーブル:IT_STUDENTSのテーブルはStandard Table(標準テーブル)なので、
DESCRIBE TABLE KIND命令により、内部テーブルのテーブルタイプを取得すると、
変数:WK_KINDにはTが入ります。
DESCRIBE(新構文)
DESCRIBE TABLE命令のLINESオプションには新構文があります。
行数(LINES)は、ABAP 7.4以降では関数「LINES( )」を使って簡潔に取得できます。
「サンプルコード」②
REPORT Z_SAMPLE157_NEW.
*主処理
START-OF-SELECTION.
*データ抽出
SELECT FROM ZTEST_TBL_001
FIELDS *
INTO TABLE @DATA(IT_STUDENTS).
*抽出できなかった場合、処理終了
IF SY-SUBRC <> 0.
MESSAGE E019(ZTEST2021). "対象データが存在しません。
ENDIF.
*内部テーブルの行数を取得(新構文)
DATA(WK_LINES) = LINES( IT_STUDENTS ).
*出力
WRITE: '<内部テーブル:IT_STUDENTS>',
/ '行数',WK_LINES.
END-OF-SELECTION.
実行結果
実行結果は同じになります。