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つです。
| 原則 | 内容 |
|---|---|
| 必要な項目だけ選ぶ | 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は、内部テーブルの各行の値を条件にして一括取得する構文です。便利ですが、いくつか落とし穴があります。
| 注意点 | 内容 |
|---|---|
| 空テーブルは全件取得になる | 駆動表が空だと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が実行します。
@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