セクション 6 / 11

Open SQL

Open SQLがデータベースを抽象化する仕組み、性能を左右する書き方の原則、そしてCDSビューへの発展を解説します。

目次を開く

Open SQLは、ABAPからデータベースにアクセスするための命令群です。データベース製品の違いを吸収し、同じコードがOracle、SQL Server、HANAのいずれでも動作します。

Open SQLが提供するもの

  • データベース非依存:SQLの方言差を意識しなくてよい
  • クライアント自動処理:WHERE句にクライアント条件が自動的に付与される
  • バッファリング:テーブルバッファを自動的に利用する
  • テーブル権限:データベースレベルの権限チェック

SELECT文の基本

基本的な取得
" 1件だけ取得
SELECT SINGLE matnr, mtart, meins
  FROM mara
  INTO @DATA(ls_mara)
  WHERE matnr = @lv_matnr.

IF sy-subrc = 0.
  " 見つかった
ENDIF.

" 複数件を内部テーブルへ
SELECT matnr, mtart, meins
  FROM mara
  INTO TABLE @DATA(lt_mara)
  WHERE mtart = 'FERT'
  ORDER BY matnr.

" 件数の取得
SELECT COUNT(*)
  FROM mara
  INTO @DATA(lv_count)
  WHERE mtart = 'FERT'.

ABAP 7.4以降では、ホスト変数の前に@を付ける新しい構文が推奨されています。この記法では、ABAPの変数とSQLの項目が明確に区別され、可読性が向上します。

性能を左右する原則

Open SQLの書き方は、プログラムの性能に直結します。以下の原則は、ABAP開発における最も重要な知識の1つです。

性能のための5原則
原則内容
必要な項目だけ選ぶSELECT * ではなく項目を明示する
必要な行だけ選ぶWHERE句で絞り込んでから取得する
ループ内でSELECTしないDB往復が件数分発生する
インデックスを意識するWHERE句の項目がインデックスの先頭から使われるように
集計はDB側で行うABAPで集計せず、SUMやGROUP BYを使う
アンチパターンと改善例
" 悪い例:ループ内でSELECT
LOOP AT lt_items INTO ls_item.
  SELECT SINGLE maktx FROM makt
    INTO ls_item-maktx
    WHERE matnr = ls_item-matnr
      AND spras = sy-langu.
ENDLOOP.

" 良い例:一度にまとめて取得してから結合
IF lt_items IS NOT INITIAL.
  SELECT matnr, maktx FROM makt
    INTO TABLE @DATA(lt_makt)
    FOR ALL ENTRIES IN @lt_items
    WHERE matnr = @lt_items-matnr
      AND spras = @sy-langu.

  SORT lt_makt BY matnr.

  LOOP AT lt_items ASSIGNING FIELD-SYMBOL(<fs>).
    READ TABLE lt_makt INTO DATA(ls_makt)
         WITH KEY matnr = <fs>-matnr BINARY SEARCH.
    IF sy-subrc = 0.
      <fs>-maktx = ls_makt-maktx.
    ENDIF.
  ENDLOOP.
ENDIF.

FOR ALL ENTRIESの注意点

FOR ALL ENTRIESは、内部テーブルの各行の値を条件にして一括取得する構文です。便利ですが、いくつか落とし穴があります。

FOR ALL ENTRIESの注意点
注意点内容
空テーブルは全件取得になる駆動表が空だとWHERE条件が消え、全件が返る
重複が自動的に除去される結果から重複行が消えるため、件数が期待と違うことがある
分割実行される内部的に複数のSQLに分割される。件数が多いと往復が増える

JOINとサブクエリ

内部結合
SELECT a~matnr, a~mtart, b~maktx
  FROM mara AS a
  INNER JOIN makt AS b
    ON a~matnr = b~matnr
  INTO TABLE @DATA(lt_result)
  WHERE a~mtart = 'FERT'
    AND b~spras = @sy-langu.

JOINを使えば、複数テーブルのデータを1回のSQLで取得できます。FOR ALL ENTRIESより効率的な場合が多いため、結合可能な場合はJOINを優先します。ただし、結合するテーブルが多すぎると、逆に遅くなることもあります。

更新系の命令

データの更新
" 挿入
INSERT ztable FROM ls_data.
INSERT ztable FROM TABLE lt_data.

" 更新
UPDATE ztable FROM ls_data.
UPDATE ztable SET status = 'C'
       WHERE matnr = @lv_matnr.

" 挿入または更新
MODIFY ztable FROM ls_data.

" 削除
DELETE FROM ztable WHERE matnr = @lv_matnr.

" コミット
COMMIT WORK.

CDSビューとコードプッシュダウン

HANAの登場により、「処理をできるだけデータベース側で行う」というコードプッシュダウンの考え方が重要になりました。

従来は、データを大量にABAPサーバへ持ってきてから加工していました。HANAでは、集計や結合をデータベース側で実行し、結果だけを受け取るほうが圧倒的に高速です。

この実現手段がCDS(Core Data Services)ビューです。ADTで定義し、複数テーブルの結合、集計、計算列、権限制御までをビューとして記述できます。ABAPからは単純なSELECTでアクセスするだけで、複雑な処理はHANAが実行します。

CDSビューの例
@AbapCatalog.sqlViewName: 'ZVMATSUM'
@AccessControl.authorizationCheck: #CHECK
define view Z_Material_Summary as
  select from mara as m
    inner join makt as t
      on m.matnr = t.matnr
{
  key m.matnr    as Material,
      m.mtart    as MaterialType,
      t.maktx    as Description
}
where t.spras = $session.system_language

📖 わからない用語は SAP用語辞典 で調べられます。

理解度チェック

このセクションの内容を確認しましょう。

確認問題 1

Open SQLのSELECT文で1行だけ取得する場合に使用する修飾子はどれか。

確認問題 2

Open SQLはデータベースの種類に依存しないため、HANAからOracle等へデータベースが変わってもABAPコードを変更する必要はない。

確認問題 3

SELECT文の実行後、データが見つからなかった場合のsy-subrcの値はどれか。

確認問題 4

複数行のデータをデータベーステーブルから内部テーブルに取得する際に使用する句はどれか。

確認問題 5

ABAPのMODIFY命令は、キーが一致する行が存在すれば更新し、存在しなければ新規挿入する。

確認問題 6

Open SQLで使用できないSQL機能はどれか。