ABAP SQL①概要

16.1 ABAP SQL

ABAP SQL(Structure Query Language)は、ABAPとデータベースを繋ぐ、データベース上のデータを加工、抽出、追加、削除するための言語です。
DBごとに方言(書き方の違い)がある「ネイティブSQL」を直接書くのではなく、ABAPのルールに沿ったSQLを書いて、DBインターフェース(Database Interface) を経由して実行します。

この仕組みのメリットは次の通りです。

・DBが変わっても、ABAP側のSQLを大きく書き換えずに済む(移植性)
・ABAPの文法・型と整合しやすく、安全にDBアクセスしやすい
・WHEREなどの条件をDB側に渡せるため、不要なデータを取らずに済む(基本の性能対策)

まずは「DBから取る(SELECT)」に慣れて、“必要な項目だけ・必要な条件だけ” を意識しましょう。

SELECT(SINGLE、UP TO n ROWS、条件式)

SELECTは、データベース上のレコードを抽出する命令です。標準テーブルでもアドオンテーブルでも、同じ書き方で取得できます。

・<項目名>には、抽出したい項目名を記載します。「*」と記述すると、全項目を抽出します。
・FROM句には、抽出先のデータベーステーブル名
・INTO句には、抽出したレコードを格納する構造名か内部テーブル名
・WHERE句には、抽出する条件(論理式)

<項目名>と<内部テーブル名>内の項目数に過不足がある場合は、エラーまたは警告が表示されるので注意が必要です。

SELECT(新構文)

S/4 HANA化に伴い、SELECT文の記述方法が変更され、より便利に扱えるようになりました。
1つのプログラム内では、従来の構文と新しい構文の両方を使うことが可能です。
ただし、1つのSELECT文の中では、旧構文と新構文を混在させず、どちらか一方の形式で統一して記述する必要があります。

構文は以下の通りです。
項目名が複数ある場合は、「,(カンマ)」で区切ります。

SELECT SINGLE

SELECT SINGLEは、対象のデータベーステーブルのプライマリーキー(データベースのレコードを一意に識別するための項目)を条件にて指定し、1件だけを取得する命令です。

「サンプルコード」①
REPORT Z_SAMPLE161.

*構造
DATA LS_TEST TYPE ZDBTBL_TEST.

*主処理
START-OF-SELECTION.

*最初の1行だけ取得
  SELECT SINGLE *
    FROM ZDBTBL_TEST
    INTO LS_TEST
    WHERE AGE = 30.

*出力
  WRITE: / LS_TEST-CLIENT, LS_TEST-NAME, LS_TEST-AGE.

SELECT文の構成

●FROM ZDBTBL_TEST
データベーステーブル:ZDBTBL_TESTから
●WHERE AGE = 30
項目:AGE(年齢)が30に一致するレコードを
●SELECT SINGLE *
1行のみ、全項目を抽出し、
●INTO LS_TEST
構造:LS_TESTに格納しなさい

実行結果

SELECT SINGLE(新構文)

SELECT SINGLEを新構文で記述すると以下の通りです。
新構文(7.4以降の書き方)では、ABAP SQL内でABAP側の変数を使うときに「@」を付けます。 また、格納先は @DATA(…) でインライン宣言できます。

「サンプルコード」②
REPORT Z_SAMPLE161_MODIFY.

*主処理
START-OF-SELECTION.

*最初の1行だけ取得
  SELECT SINGLE *
    FROM ZDBTBL_TEST
    INTO @DATA(LS_TEST)
    WHERE AGE = 30.

*出力
  WRITE: / LS_TEST-CLIENT, LS_TEST-NAME, LS_TEST-AGE.

SELECT文の構成

●FROM ZDBTBL_TEST
データベーステーブル:ZDBTBL_TESTから
●WHERE AGE = 30
項目:AGE(年齢)が30に一致するレコードを
●SELECT SINGLE *
1行のみ、全項目を抽出し
●INTO@DATA(LS_TEST)
構造:LS_TESTに格納しなさい

実行結果

実行結果は同じになります。

SELECT UP TO nn ROWS

SELECTUP TO nn ROWSでは、「最大nn件まで」取得する指定です。データを特定のレコード数のみ取得することができます。(※ nn は任意の数字。)

「<DBテーブル>から抽出した項目を<構造>に格納し、編集後に<内部テーブル>に格納する」
という処理をnn回繰り返す、という処理になります。

「サンプルコード」①
REPORT Z_SAMPLE162.

START-OF-SELECTION.

"上位3件を取得(SCOREの高い順)
  SELECT *
     FROM ZDBTBL_TEST_K
     ORDER BY SCORE DESCENDING
     INTO TABLE @DATA(LT_STUDENTS)
     UP TO 3 ROWS.

"ZRESULTに「合格」を設定(仕様通り:全件固定)
  LOOP AT LT_STUDENTS INTO DATA(LS_STUDENT).
    LS_STUDENT-ZRESULT = '合格'.
    MODIFY LT_STUDENTS FROM LS_STUDENT INDEX SY-TABIX.
  ENDLOOP.

  "出力
  LOOP AT LT_STUDENTS INTO DATA(LS_OUT).
    WRITE: /
      LS_OUT-NAME,
      LS_OUT-SCORE,
      LS_OUT-TYPE,
      LS_OUT-ZRESULT.
  ENDLOOP.

旧来の 「SELECT … ENDSELECT」 は「1件ずつ取り出す」形ですが、まとめて取得(INTO TABLE)する方が読みやすく、実務でも一般的です。

実行結果
サンプルコードの補足

データベーステーブル:ZDBTBL_TEST_Kから、レコードを抽出し、抽出したデータを編集して、内部テーブル:LT_STUDENTSに格納しています。

ORDER BY SCORE DESCENDING はソート処理と呼ばれ、データを並び替えます。
SCORE(得点)をDESCENDING(降順)で並び替えなさい、という命令です。
得点が高い順に並び替えて、データを取得しています。

その後、取得したデータを編集していきます。
取得した構造:LS_STUDENTの項目:ZRESULTに 「合格」の文字を代入します。
編集した構造:LS_STUDENTを内部テーブル:LT_STUDENTSに格納します。
この処理を3回(UP TO 3 ROWS)繰り返します。

最後に内部テーブル:LT_STUDENTSを出力します。
(テーブル:ZDBTBL_TEST_Kのレコードを、得点が高い順に並び替え上位3名を出力するプログラムになっています。)

SELECT(条件式)

条件式の部分には、抽出条件を記述します。主にWHERE句で使用します。

※1%01 :%は、任意の文字列。%01であれば、下2桁が01のものを抽出します。
※2sel :SELECT-OPTIONSで宣言した項目名またはレンジテーブルを指定できます。

「サンプルコード」②
REPORT Z_SAMPLE163.

DATA GT_STUDENTS TYPE STANDARD TABLE OF ZDBTBL_TEST_K WITH EMPTY KEY.

START-OF-SELECTION.

  SELECT *
    FROM ZDBTBL_TEST_K
    WHERE TYPE = '文系'
    ORDER BY SCORE DESCENDING
    INTO TABLE @GT_STUDENTS
    UP TO 3 ROWS.

  IF GT_STUDENTS IS INITIAL.
    MESSAGE '該当データがありません。' TYPE 'S'.
    RETURN.
  ENDIF.

  LOOP AT GT_STUDENTS INTO DATA(LS_STUDENT).
    LS_STUDENT-ZRESULT = '合格'.
    MODIFY GT_STUDENTS FROM LS_STUDENT.
  ENDLOOP.

  LOOP AT GT_STUDENTS INTO DATA(LS_OUT).
    WRITE: / LS_OUT-NAME, LS_OUT-SCORE, LS_OUT-TYPE, LS_OUT-ZRESULT.
  ENDLOOP.

実行結果

SELECT INTO TABLE

SELECT … INTO TABLE は、条件に一致するレコードをまとめて内部テーブルに格納します。

  • • 1件だけ欲しい → SELECT SINGLE
  • • 最大n件 → UP TO n ROWS
  • • 複数件を一括取得 → INTO TABLE

実務では、基本は INTO TABLE、必要に応じて件数制限や並び替えを組み合わせます。

<DBテーブル>から、<条件式>に一致するレコードの<項目>を抽出し、 <内部テーブル>に格納します。内部テーブルには、複数のレコードが一括で格納されます。対象レコードが1件の場合は、1件のみ格納されます。

SELECT SINGLE、および、SELECT UP TO nn ROWSとの違い

SELECT SINGLE:対象レコードを1件抽出し、構造に格納します。

SELECT UP TO nn ROWS:対象レコードを1件ずつ抽出し、構造に格納することを、nn回繰り返します。

SELECT INTO TABLE:対象レコードを一括で抽出し、内部テーブルに格納します。

「サンプルコード」①
REPORT Z_SAMPLE164.

*型定義
TYPES:
  BEGIN OF TYP_LINE,
    NUM             TYPE ZTEST_TBL_001-NUM,
    LASTNAME  TYPE ZTEST_TBL_001-LASTNAME,
    FIRSTNAME TYPE ZTEST_TBL_001-FIRSTNAME,
END OF TYP_LINE.
*変数定義 
DATA:
  IT_STUDENTS  TYPE STANDARD TABLE OF TYP_LINE,
  ST_STUDENTS TYPE TYP_LINE.

*選択画面定義
PARAMETERS: 
  P_CLASS TYPE ZTEST_TBL_001-CLASS DEFAULT ‘A’, "組

*主処理
START-OF-SELECTION.

*DBテーブル:ZTEST_TBL_001から、
*CLASS(組)が選択画面の条件に一致するレコードの
*項目:NUM(出席番号)、LASTNAME(姓)、FIRSTNAME(名)を
*複数件一括で抽出し、内部テーブルに格納
  SELECT NUM             “出席番号
                 LASTNAME  “姓
                 FIRSTNAME “名
      FROM ZTEST_TBL_001
        INTO TABLE IT_STUDENTS 
    WHERE CLASS  = P_CLASS. "組

*抽出できなかった場合、処理終了
  IF SY-SUBRC <> 0.
    MESSAGE E019(ZTEST2021). “対象データが存在しません
  ENDIF.

*抽出結果を出力
  WRITE: / '出席番号',
              15 '姓',
              30 '名'.
  LOOP AT IT_STUDENTS INTO ST_STUDENTS.
    WRITE: /   ST_STUDENTS-NUM,             "出席番号
                15 ST_STUDENTS-LASTNAME,  "姓
                30 ST_STUDENTS-FIRSTNAME. "名
  ENDLOOP.

END-OF-SELECTION.

補足:SY-SUBRCについて

SY-SUBRC は、直前の処理結果を表す代表的なシステム変数です。
詳しくは20章で学ぶため、 当章ではABAP命令が失敗すると「0以外の数字」が格納される変数、と理解しましょう。

Open SQLでは次の理解でOKです。

・0:取得できた(対象がある) ・4:取得できない(対象がない)
IF SY-SUBRC <> 0.
<処理>
ENDIF.
上記のように記述すると、直前の処理が失敗したら<処理>を実行する、という意味になります。

また、MESSAGE E019(ZTEST2021) はエラーメッセージを出力して処理を終了する、という命令です。
詳しくは18章で学習するため、プログラムの流れが理解できればOKです。

SELECT INTO TABLE(新構文)

SELECT INTO TABLEを新構文で記述すると以下の通りです。
先述の通り、SELECTの新構文では、格納用の変数/構造/内部テーブル名の前に「@」をつけます。
また、選択画面項目名の前にも「@」をつける必要があります。

SELECTの新構文では項目の後に「,(カンマ)」が必要です。
旧構文と書き方に違いがあるため、気をつけましょう。

「サンプルコード」②
REPORT Z_SAMPLE164_MODIFY.

*選択画面定義
PARAMETERS: 
  P_CLASS TYPE ZTEST_TBL_001-CLASS DEFAULT ‘A’, "組

*主処理
START-OF-SELECTION.



*DBテーブル:ZTEST_TBL_001から、
*CLASS(組)が選択画面の条件に一致するレコードの
*項目:NUM(出席番号)、LASTNAME(姓)、FIRSTNAME(名)を
*複数件一括で抽出し、内部テーブルに格納
  SELECT FROM ZTEST_TBL_001
   FIELDS NUM,             “出席番号
                 LASTNAME,  “姓
                 FIRSTNAME, “名
  WHERE CLASS  = @P_CLASS. "組
        INTO TABLE  @DATA(LT_STUDENTS)

*抽出できなかった場合、処理終了
  IF SY-SUBRC <> 0.
    MESSAGE E019(ZTEST2021). “対象データが存在しません
  ENDIF.

*抽出結果を出力
  WRITE: / '出席番号',
              15 '姓',
              30 '名'.
  LOOP AT LT_STUDENTS INTO DATA(LS_STUDENTS).
    WRITE: /   LS_STUDENTS-NUM,             "出席番号
                15 LS_STUDENTS-LASTNAME,  "姓
                30 LS_STUDENTS-FIRSTNAME. "名
  ENDLOOP.

END-OF-SELECTION.

実行結果は同じになります。


NEXT>> 16.2 デバッグ機能

研修の詳細はこちら