【ABAP】基本構文:繰り返し(DO、WHILE、LOOP、SELECT、PROVIDE)

登場人物紹介

三崎レイナ
社会人1年目。新卒でITコンサルティングファームに就職。初配属がSAPプロジェクトにアサインされる。SAPがわからないことだらけで悩んでいたところ、会社の先輩にSAPラボの所長を紹介され、毎週末に所長とSAPのお勉強中!

博士
SAPラボの所長。SAP大好き博士!SAP導入プロジェクトを構想策定~運用保守まであらゆるフェーズを数多く経験。
いまは優しきおじいちゃんだが、プロマネバリバリの時代はかなり怖かったらしい。現在は引退し、SAPの後進育成と啓蒙活動に従事中!

この記事を読むメリット

  • DO~ENDDO命令やWHILE~ENDWHILE命令を使用して、繰り返し処理を作成できるようになります。
  • LOOP~ENDLOOP命令を使用して、内部テーブルの繰り返し処理を作成できるようになります。
博士

今回はABAPの繰り返し(ループ)について説明するぞい!

ABAPでの繰り返し処理(ループ処理)は、プログラム内で同じ一連の命令を繰り返し行うために使用されます。繰り返し処理をマスターすることで、大量データの効率的な処理やコードの再利用性と可読性の向上が実現し、システム全体の性能向上や開発プロセスの効率化が期待できます。頻繁に使用されるのでしっかりマスターしておきましょう。

この記事のポイント

繰り返しについて

繰り返し処理とは、同じ一連の命令や処理を複数回実行することを指します。これにより、データの集計や変換、処理の反復などを効率的に行うことができます。繰り返し処理は、大量のデータや複雑なロジックを扱う際に特に重要であり、コードの再利用性やメンテナンス性を向上させる効果もあります。

ABAPでは、繰り返しを実現するために、”DO命令“や”WHILE命令“を使用します。また、内部テーブルの各行に対して繰り返し処理を行うには、”LOOP命令“を使用します。その他にも”SELECT命令“や”PROVIDE命令“を使用して繰り返し処理を作成することも可能です。

DO命令(DO~ENDDO)

博士

まずはDO命令じゃ。
DO命令は、指定した回数だけ繰り返し処理を行うための命令だぞい!

ABAPのDO命令は、指定された回数だけ繰り返し処理を行うか、”EXIT命令”が実行されるまで繰り返し処理を行います。指定回数の繰り返し処理が必要な場合に便利ですが、回数を指定しない場合は無限ループを発生させてしまう可能性があるため、注意が必要です。

構文
 DO n TIMES.
  繰り返し実行する処理.
 ENDDO.
 ※「n」は繰り返し回数を指定します。
 ※実行回数を指定しないパターンは、「n TIMES」の部分を省略します。

博士

DO命令の構文ルール自体はシンプルじゃ!
DO~ENDDOでループのブロック(かたまり)を定義して、その中に繰り返したい処理を記述すればいいだけじゃ。
実際に使用例を見ていくぞい!

1、回数を指定するパターン

使用例
* DO命令を使用して1から10までの数を出力する
DATA: lv_counter TYPE i.

DO 10 TIMES.
  lv_counter = sy-index.
  WRITE: / '繰り返し回数:', lv_counter.
ENDDO.

このプログラムでは、DO命令を使用してから1から10までの数を出力しています。”sy-index”は現在のループインデックスを示し、1から始まります。
※SY-INDEXはシステム項目の1つで、よく使用されます。

実行結果

ABAP繰り返し(DO命令)サンプルプログラム実行結果

2、回数を指定しないパターン

使用例
DATA: lv_counter TYPE i VALUE 0.

DO.
  lv_counter = lv_counter + 1.
  WRITE: / '繰り返し回数:', lv_counter.
  IF lv_counter >= 10.
    EXIT.
  ENDIF.
ENDDO.

このプログラムでは、DO命令内でカウントアップし、カウンターが10に達したら”EXIT命令”で繰り返しを終了します。

実行結果

ABAP繰り返し(DO命令)サンプルプログラム実行結果

【重要】DO命令の注意点

  • 無限ループに注意
    DO命令では回数を指定しない場合、無限ループが発生する可能性があります。無限ループを避けるためには、必ず終了条件を設定する必要があります。
  • EXIT命令の使用
    特定の条件下でループを終了する場合は、”EXIT命令”を使用します。”EXIT命令”は、ループの途中で処理を終了し、ループの外側にある次の命令に移動します。
無限ループになる例
DO.
 WRITE: / 'こんにちは!'.
ENDDO.

上記の例だと、「こんにちは!」と出力する処理が無限に繰り返されます。
無限ループを続けるとメモリが圧迫され、いずれショートダンプが起きます。
回避するためには回数を指定するか、”EXIT命令”を使用して繰り返しの終了条件を設定します。

WHILE命令(WHILE~ENDWILE)

博士

次はWHILE命令じゃ。
WHILE命令は、指定した条件が真である限り、繰り返し処理を行うための命令だぞい!

ABAPのWHILE命令は、指定された条件が満たされている間、繰り返し処理を行います。この命令は、条件が変化するまで繰り返し処理を行いたい場合に便利です。ただし、条件が永遠に満たされ続ける場合は無限ループを発生させてしまう可能性があるため、注意が必要です。

構文
 WHILE 条件.
  繰り返し実行する処理.
 ENDWHILE.
 ※DO命令は繰り返しを行う「回数を指定しましたが、WHILE命令は繰り返し行う「条件」を指定するのが大きな違いです。

博士

WHILE命令の構文ルールもシンプルじゃ!
WHILE~ENDWHILEでループのブロック(かたまり)を定義して、その中に繰り返したい処理を記述すればいいだけじゃ。
実際に使用例を見ていくぞい!

使用例
DATA: lv_counter TYPE i VALUE 1.

WHILE lv_counter <= 10.
  WRITE: / '繰り返し回数:', lv_counter.
  lv_counter = lv_counter + 1.
ENDWHILE.

このプログラムでは、lv_counterが10以下の間、繰り返し処理を行います。ループ内でカウントアップし、条件が満たされなくなるとループが終了します。

実行結果

ABAP繰り返し(DO命令)サンプルプログラム実行結果

【重要】WHILE命令の注意点

  • 無限ループに注意
    WHILE命令では条件が常に真の場合、無限ループが発生する可能性があります。無限ループを避けるためには、必ず条件が満たされなくなるようにループ内で適切な処理を行う必要があります。
  • EXIT命令の使用
    特定の条件下でループを終了する場合は、”EXIT命令”を使用します。”EXIT命令”は、ループの途中で処理を終了し、ループの外側にある次の命令に移動します。
博士

“EXIT命令”は繰り返し処理の中で非常に重要な命令なので覚えておくのじゃ!

使用例
DATA: lv_counter TYPE i VALUE 0.

WHILE lv_counter < 10.
  lv_counter = lv_counter + 1.
  WRITE: / lv_counter.
  IF lv_counter = 5.
    EXIT.
  ENDIF.
ENDWHILE.

このプログラムでは、カウンターが10未満の間、繰り返し処理を行いますが、カウンターが5に達した時点で”EXIT命令”によりループを終了します。

実行結果

ABAP繰り返し(WHILE命令)サンプルプログラム実行結果

博士

ここまでで、ABAPの”DO命令“、”WHILE命令“を説明したぞい。
ポイントをまとめておいたぞい!

・DO命令:固定回数の繰り返しに適している
・WHILE命令:動的条件に基づく繰り返しに適している

各命令の特性と注意点を理解し、適切なシナリオで使い分けることが、効率的なABAPプログラミングの鍵となります。

LOOP命令(LOOP~ENDLOOP)

博士

次はLOOP命令じゃ。
LOOP命令は内部テーブルの各行に対して繰り返し処理を行うために使用されるぞい!

ABAPのLOOP命令は、内部テーブルの各行に対して繰り返し処理を行うための命令です。この命令は内部テーブルのすべての行や、特定の条件を満たす行に対して処理を行う場合に便利です。ただし、内部テーブルの範囲や条件を適切に設定しないと、不要な行まで処理してしまう可能性があるため、注意が必要です。

構文
 LOOP AT 内部テーブル INTO 作業領域.
  繰り返し実行する処理.
 ENDLOOP.
 ※LOOP命令は内部テーブルの各行が順番に作業領域に一時的に読み込まれ、繰り返し処理が実行されます。

博士

まずは簡単な使用例を見ていくぞい!

使用例
DATA: lt_sflight TYPE TABLE OF sflight,
      ls_row   TYPE sflight.

" フィルタ条件を使用してデータを制限
SELECT * FROM sflight INTO TABLE lt_sflight UP TO 10 ROWS.

LOOP AT lt_sflight INTO ls_row.
  WRITE: / ls_row-carrid, ls_row-connid, ls_row-fldate.
ENDLOOP.

このプログラムでは、SFLIGHTテーブルからデータを選択し、そのデータを内部テーブルlt_sflightに格納します。その後、LOOP命令を使用して各行をループし、航空会社ID、フライト番号、フライト日付を出力します。

実行結果

ABAP繰り返し(LOOP命令)サンプルプログラム実行結果①

博士

例えば、フライトごとの座席数の合計を計算する場合は下記のようにコードを作成するのじゃ!

使用例
DATA: lt_sflight TYPE TABLE OF sflight,
      ls_sflight TYPE sflight,
      lv_total_seats TYPE i.

SELECT * FROM sflight INTO TABLE lt_sflight WHERE carrid = 'LH'.

LOOP AT lt_sflight INTO ls_sflight.
  lv_total_seats = lv_total_seats + ls_sflight-seatsmax.
ENDLOOP.

WRITE: / 'Total Seats for LH:', lv_total_seats.

このプログラムでは、「carridが’LH’のフライトに対して座席数の合計をLOOP命令を使用して計算し、出力します。

実行結果

ABAP繰り返し(LOOP命令)サンプルプログラム実行結果②

博士

DO命令やWHILE命令と同様、LOOP命令自体はシンプルじゃ。しかし、オプションを使用して特定の条件や範囲を設定することで、より柔軟で効率的な繰り返し処理が可能になるぞい。

オプション①:WHERE

特定の条件を満たす行だけを処理するために使用します。条件に合致する行だけを処理することで、不要な処理を減らすことができます。

使用例
DATA: lt_sflight TYPE TABLE OF sflight,
      ls_sflight TYPE sflight.

" SFLIGHTテーブルからデータを取得
SELECT * FROM sflight INTO TABLE lt_sflight.

" WHEREオプションを使用して条件を満たす行をループ
LOOP AT lt_sflight INTO ls_sflight WHERE carrid = 'LH'.
  WRITE: / ls_sflight-carrid, ls_sflight-connid, ls_sflight-fldate.
ENDLOOP.

このプログラムでは、「carrid」が”LHの行だけをループします。

実行結果

ABAP繰り返し(LOOP命令、WHERE)サンプルプログラム実行結果③

オプション②:FROM / TO

テーブルの特定の範囲の行だけを処理するために使用します。処理する行の範囲を限定することで、処理時間を短縮できます。

使用例と実行結果
DATA: lt_sflight TYPE TABLE OF sflight,
      ls_sflight TYPE sflight.

" SFLIGHTテーブルからデータを取得
SELECT * FROM sflight INTO TABLE lt_sflight.

" FROM/TOオプションを使用して指定した範囲の行をループ
LOOP AT lt_sflight INTO ls_sflight FROM 10 TO 20.
  WRITE: / ls_sflight-carrid, ls_sflight-connid, ls_sflight-fldate.
ENDLOOP.

この例では、内部テーブルの10行目から20行目までをループします。

実行結果

ABAP繰り返し(LOOP命令、FROM/TO)サンプルプログラム実行結果③

フィールドシンボル

フィールドシンボルはポインタのようなもので、直接データを操作でき、より柔軟なデータ操作が可能になります。

使用例
DATA: lt_sflight TYPE TABLE OF sflight.
FIELD-SYMBOLS: <fs_sflight> TYPE sflight.

" SFLIGHTテーブルからデータを取得
SELECT * FROM sflight INTO TABLE lt_sflight WHERE carrid = 'LH'.

" フィールドシンボルを使って内部テーブルの各行をループし、データを変更
LOOP AT lt_sflight ASSIGNING <fs_sflight>.
  WRITE: / '最大座席数 変更前:', <fs_sflight>-seatsmax.
  <fs_sflight>-seatsmax = <fs_sflight>-seatsmax + 10.
  WRITE: '変更後:', <fs_sflight>-seatsmax.
ENDLOOP.

このプログラムでは、ASSIGNING句を使ってフィールドシンボルに各行を割り当て、直接内部テーブルのデータにアクセスして、各フライトの最大座席数を10増加させています。

実行結果

ABAP繰り返し(LOOP命令、フィールドシンボル)サンプルプログラム実行結果⑦

【重要】LOOP命令の注意点

  • 無限ループに注意
    LOOP命令を使用する際に、LOOPしている内部テーブルにレコードを挿入(APPEND)し続けてしまい無限ループになる可能性があります。そういったことが無いよう無限ループを防ぐようにしましょう。
  • パフォーマンス
    大量のデータを持つ内部テーブルに対してLOOP命令を使用する場合、パフォーマンスに注意が必要です。適切なオプション(WHEREやFROM / TO)を使用して、効率的にデータを処理することが重要です。
  • 作業領域(ワークエリア)の初期化
    LOOP命令の外で作業領域を初期化する必要があります。作業領域が適切に初期化されていないと、前回のループの値が残ってしまう可能性があります。
  • テーブルの変更
    LOOP内で内部テーブルのデータを変更すると、予期しない動作を引き起こす可能性があるため、慎重に操作する必要があります。(例:LOOP内で内部デーブルのデータを削除するとインデックスがずれてしまうなど)

SELECT命令(SELECT~ENDSELECT) ※非推奨

SELECT命令は、データベーステーブルからデータを取得するための命令です。
SELECT命令で取得したデータを処理する際には、LOOP命令が頻繁に使用されますが、SELECT~ENDSELECTでブロックを作成すると、条件と一致したデータがなくなるまで1件ずつレコードの取得とブロック内に記載した処理がループして処理されます。
※ただし、SELECT~ENDSELECTはパフォーマンス悪化の原因となるため、非推奨です。

博士

現在は非推奨の使い方の為、必ず覚える必要はないぞい!

構文
 SELECT * FROM (テーブル名) INTO (変数または作業領域).
  繰り返し実行する処理.
 ENDSELECT.
 ※WHEREオプションや”SELECT SINGLE”、”UP TO n ROWS”を使用することで、繰り返し処理を行う対象のデータを絞ることができます。

使用例
* データ宣言
DATA: lv_carrid   TYPE sflight-carrid,   "航空会社ID
      lv_connid   TYPE sflight-connid,   "フライト番号
      lv_fldate   TYPE sflight-fldate,   "フライト日
      lv_price    TYPE sflight-price.    "航空運賃

* 選択画面の宣言
PARAMETERS: p_carrid TYPE sflight-carrid.  "ユーザー入力用のパラメータ

* メイン処理
START-OF-SELECTION.

* SFLIGHTテーブルからデータを選択
  SELECT carrid
         connid
         fldate
         price
    INTO (lv_carrid, lv_connid, lv_fldate, lv_price)
    FROM sflight
    WHERE carrid = p_carrid.

* 取得したデータの出力
    WRITE: / '航空会社ID:', lv_carrid,
           'フライト番号:', lv_connid,
           'フライト日:', lv_fldate,
           '運賃:', lv_price.

  ENDSELECT.

* データが見つからなかった場合のメッセージ
  IF sy-subrc <> 0.
    WRITE: / '指定された航空会社IDに対するフライトは見つかりませんでした。'.
  ENDIF.

このプログラムは、ユーザーが入力した航空会社ID(p_carrid)に基づいて、SFLIGHTテーブルから該当するフライト情報(航空会社ID、フライト番号、フライト日、運賃)を取得し、各フライトの詳細を画面に出力します。データが見つからなかった場合には、「指定された航空会社IDに対するフライトは見つかりませんでした。」というメッセージが表示されます。

実行結果

ABAP繰り返し(SELECT命令)サンプルプログラム実行結果⑧

システム項目:SY-SUBRC

SELECT命令で1件でもデータを取得することができれば、「SY-SUBRC」に0が入ります。
「SY-SUBRC」が0以外の場合は対象のデータが1件も存在しなかったなどを示します。

PROVIDE命令(PROVIDE~ENDPROVIDE) ※補足

PROVIDE~ENDPROVIDEは、複数の内部テーブルからデータを効率的に取得し、指定したキー範囲内で重複するレコードを結合して処理するための命令です。例えば、指定した期間内で2つの内部テーブルのデータをマッチングし、一致するデータを取得して処理することができます。ただし、大量のデータを処理する場合、PROVIDE命令のパフォーマンスが低下することがあり、その場合はSELECT文を使用してデータを結合した方が効率的な場合があります。

博士

頻繁に使う命令ではないので、こんな命令もあるんだ程度で覚えておけば大丈夫だぞい!

構文
 PROVIDE FIELDS (項目1 項目2…) FROM (テーブル名1) INTO (作業領域1)
                VALID (フラグ1) BOUNDS (検索項目1) AND (検索項目2)
      FIELDS (項目1 項目2…) FROM (テーブル名2) INTO (作業領域2)
                VALID (フラグ2) BOUNDS (検索項目3) AND (検索項目4)
      BETWEEN (検索範囲開始) AND (検索範囲終了).
  繰り返し実行する処理.
 ENDPROVIDE.
 ※VALID:データが有効な場合にセットされるフラグを指定します。
 ※BOUNDS:検索のための範囲を指定する項目を指定します。
 ※BETWEEN:検索する範囲を指定します。範囲外のデータは無視されます。

使用例
* 給与情報を格納する内部テーブルの定義
DATA: BEGIN OF lt_salary OCCURS 0,
        salary TYPE p0008-bet01,    " 給与金額
        begda  TYPE p0008-begda,    " 開始日
        endda  TYPE p0008-endda,    " 終了日
      END OF lt_salary.

* 住所情報を格納する内部テーブルの定義
DATA: BEGIN OF lt_address OCCURS 0,
        city TYPE p0006-ort01,      " 都市
        begda TYPE p0006-begda,     " 開始日
        endda TYPE p0006-endda,     " 終了日
      END OF lt_address.

* ワークエリアの定義
DATA: wa_salary LIKE lt_salary,
      wa_address LIKE lt_address,
      flag1(1) TYPE c,              " フラグ1:給与情報の有効性
      flag2(1) TYPE c.              " フラグ2:住所情報の有効性

* 内部テーブルにデータを追加(サンプルデータ)
APPEND VALUE #( salary = '5000' begda = '20230101' endda = '20230731' ) TO lt_salary.  " サンプル給与データ1
APPEND VALUE #( salary = '6000' begda = '20240101' endda = '20240731' ) TO lt_salary.  " サンプル給与データ2
APPEND VALUE #( salary = '7000' begda = '20250601' endda = '20251231' ) TO lt_salary.  " サンプル給与データ3
APPEND VALUE #( city = 'Tokyo' begda = '20230101' endda = '20230731' ) TO lt_address.  " サンプル住所データ1
APPEND VALUE #( city = 'Osaka' begda = '20240201' endda = '20240631' ) TO lt_address.  " サンプル住所データ2
APPEND VALUE #( city = 'Fukuoka' begda = '20250101' endda = '20250601' ) TO lt_address.  " サンプル住所データ3

* PROVIDE命令の使用
* 指定した範囲で一致を検索する
PROVIDE FIELDS * FROM lt_salary INTO wa_salary VALID flag1 BOUNDS begda AND endda
        FIELDS * FROM lt_address INTO wa_address VALID flag2 BOUNDS begda AND endda
        BETWEEN '20230101' AND '20251231'.

* データの出力
  WRITE: / wa_salary-begda, wa_salary-endda,          " 給与データの開始日と終了日
           '給与:', wa_salary-salary, flag1,          " 給与金額とフラグ1
           '住所:', wa_address-city, flag2.           " 住所(都市)とフラグ2

ENDPROVIDE.

このプログラムは、従業員の給与情報と住所情報を保持する内部テーブルを作成し、それらのデータを範囲指定して検索・表示するものです。具体的には、指定された期間に基づいて給与と住所を一致させ、結果を出力します。

実行結果

ABAP繰り返し(PROVIDE命令)サンプルプログラム実行結果

無限ループを回避する方法

無限ループは、処理が永遠に繰り返されることを指します。この状態は、プログラム内で処理を終了するための条件が適切に設定されていないか、条件が常に真となる場合に発生します。無限ループは、その機能だけでなく、システム全体に影響を及ぼす可能性があります。例えば、サーバへの負荷をかけ続けることになり、システム全体のパフォーマンスに悪影響を与える可能性があります。

大前提として、繰り返し回数や条件を適切に指定することは、無限ループを避けるために非常に重要です。ループを抜ける条件を明確に設定することで、処理が永遠に続かず、必要なタイミングでループが終了します。

強制終了命令の使用

EXIT命令、CONTINUE命令、およびCHECK命令は、ループを強制的に抜けるための命令です。これらの命令を適切に使用することで、無限ループを防ぐことができます。

  • EXIT命令
    現在のループを終了し、ループの外側にある次の命令に移動します。これは、特定の条件が満たされた場合に、ループを強制的に終了させるために使用します。
  • CONTINUE命令
    現在のループの処理をスキップし、次のループサイクルに進みます。これは、特定の条件が満たされた場合に、その回の処理をスキップするために使用します。
  • CHECK命令
    現在のループの条件をチェックし、条件が満たされない場合はその回の処理をスキップして次のループサイクルに進みます。これは、特定の条件が満たされる場合にのみ処理を続行するために使用します。

まとめ

ABAPの繰り返し処理の、DO命令とWHILE命令、そしてLOOP命令を紹介しました。これらの命令を適切に使用することで、効率的かつ保守性の高いコードを作成することができます。
DO命令は指定回数の繰り返し処理に、WHILE命令は条件が満たされている間の繰り返し処理に適しています。一方、LOOP命令は内部テーブルの各行に対する繰り返し処理に使用されます。いずれの繰り返し命令を使用するにしても、無限ループを防ぐために、条件とループ内の処理を慎重に設計する必要があります。

博士

この記事を通じて基本を理解した後、実際の業務シナリオでの適用方法を考えると良いぞい!

レイナ

繰り返し処理をマスターすることで、より効率的なプログラムが作成できそうです!やってみます!

★★★SAPラボのライター募集★★★

SAPラボでは、SAPの知識を活かして副業をしたい方を募集してるのじゃ!

SAPラボのライターの特徴 

・ライティング初心者OK!
・報酬高単価!
・業務委託契約なので副業として最適!

SAP記事執筆者としての活動実績として利用可能なので、転職時や案件探しの際に企業へのアピール材料にもなります。

募集要項

・SAP導入や運用保守プロジェクトへの参画経験1年以上

ご応募/お問合せ先

info@sap-career.com

少しでもご興味ある方、ぜひお気軽にご連絡下さい!

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

新卒でSAPエンジニアとしてABAPでの新規開発や保守業務を担当。
業務内容としてはロジ系(MM/SD)がメインで、ABAPの開発が最も得意。

この記事のポイント