ABAP New open SQL:INTO TABLEの記述場所について

私の悩みを聞いてください☆

Open SQLを記述していると、「INTO TABLE」をどこに書くか悩むことが多々ありました。
いままで私は、SELECT xxxx INTO TABLE xxxx FROM 〜の順番で書いていました。
理由として、項目および項目の並び順は、格納する内部テーブルと密接に関連するので、
つながりが深いものは可能な限り近くに記述するほうが、
コードが読みやすく保守性も良くなると考えていたからです。

しか〜し(笑)、数週間前から改めます。



INTO TABLE xxxxは最後に書く!!!



理由としては、ABAP 7.5になってからいくつか機能拡張(SQL関数、UNION句等)して、
これらを使うと、INTO TABLE xxxxは最後に書かないと...(これから先が重要!!)



文法エラーで有効化できない!!!



もう一度言います。



INTO TABLE xxxxは最後に書く!!!



つい先ほどまで、過去に書いた記事のソースコードをすべて書き直しました。(ふ〜ぅ)
でもさぁ〜本当に最後に書くの普及するのかなぁ〜!?
(Classic Open SQLだと、エラーだし...)

しつこいけれど、もう一度言います。



INTO TABLE xxxxは最後に書く!!!



でした☆
今日は「!」が多いなぁ〜。


検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
SQL
Open SQL
New Open SQL
Classic Open SQL
SAP HANA
Code to Data
Code Pushdown

以上

ABAP New open SQL:SQL関数拡張(1) on ABAP 7.50

ABAP New open SQLSQL関数拡張(1) on ABAP 7.50

今回は、「SQL関数拡張(1) on ABAP 7.50」ということで、CONCAT()を使った例を示す。
購買伝票明細EKPOを使って、
購買伝票番号と購買伝票の明細番号の文字列結合と、
プラントと保管場所の文字列結合をしてみる。
そして、区切り文字として「-」を付加する。

購買伝票番号と購買伝票の明細番号は両方とも必須項目なのでシンプルになるが、
プラントと保管場所については保管場所が任意項目のため、
プラントのみの場合は区切り文字として「-」を取るようにする。

早速SELECT文を...

L085:  SELECT
L086:      CONCAT( CONCAT( ti0~ebeln,'-' ),ti0~ebelp ) AS c1,
L087:      CASE
L088:        WHEN ti0~werks = @space AND ti0~lgort = @space THEN @space
L089:        WHEN ti0~werks <> @space AND ti0~lgort = @space THEN ti0~werks
L090:        WHEN ti0~werks = @space AND ti0~lgort <> @space THEN CONCAT( '     ', ti0~werks )
L091:        ELSE CONCAT( CONCAT( ti0~werks,'-' ),ti0~lgort ) END AS c2,
L092:      ti0~werks,
L093:      ti0~lgort
L094:    FROM ekpo AS ti0
L095:    ORDER BY
L096:      ti0~ebeln,
L097:      ti0~ebelp
L098:    INTO TABLE @DATA(lt_data).

購買伝票番号と購買伝票の明細番号はL086に記述している。
SQL関数は入れ子にして使うことも可能である。
3個以上の項目を結合するときはこんな感じ。

プラントと保管場所はL087-L091に記述している。
プラントは必須項目であるが今回は任意項目として記述してみた。
よって4通りのパターンがあるためそれぞれ記述している。
L092-L093は参考として素のデータを出力している。

今回気づいたのだが、
「INTO TABLE〜」は最後の行に書く必要がある。(エラーで有効化できなかった)
ABAP 7.50になって、ABAP CDSの文法を意識しているのかもしれない。
(近々アップロード済みのソースを修正します)→修正しました。2017-10-18


L001:*&---------------------------------------------------------------------*
L002:*& Report Y_SQL_CONSOLE
L003:*&---------------------------------------------------------------------*
L004:*&
L005:*&---------------------------------------------------------------------*
L006:REPORT y_sql_console.
L007:
L008:*-----------------------------------------------------------------------
L009:* グローバル変数
L010:*-----------------------------------------------------------------------
L011:DATA gv_subrc TYPE sy-subrc.
L012:
L013:*-----------------------------------------------------------------------
L014:* 選択画面
L015:*-----------------------------------------------------------------------
L016:*
L017:DATA gv_char1 TYPE char10.
L018:TYPES gtrt_char1 LIKE RANGE OF gv_char1.
L019:SELECT-OPTIONS s_char1 FOR gv_char1.
L020:*
L021:DATA gv_char2 TYPE char10.
L022:TYPES gtrt_char2 LIKE RANGE OF gv_char2.
L023:SELECT-OPTIONS s_char2 FOR gv_char2.
L024:*
L025:DATA gv_numc1 TYPE numc08.
L026:TYPES gtrt_numc1 LIKE RANGE OF gv_numc1.
L027:SELECT-OPTIONS s_numc1 FOR gv_numc1.
L028:*
L029:DATA gv_numc2 TYPE numc08.
L030:TYPES gtrt_numc2 LIKE RANGE OF gv_numc2.
L031:SELECT-OPTIONS s_numc2 FOR gv_numc2.
L032:*
L033:DATA gv_dats1 TYPE dats.
L034:TYPES gtrt_dats1 LIKE RANGE OF gv_dats1.
L035:SELECT-OPTIONS s_dats1 FOR gv_dats1.
L036:*
L037:DATA gv_dats2 TYPE dats.
L038:TYPES gtrt_dats2 LIKE RANGE OF gv_dats2.
L039:SELECT-OPTIONS s_dats2 FOR gv_dats2.
L040:*
L041:DATA gv_tims1 TYPE tims.
L042:TYPES gtrt_tims1 LIKE RANGE OF gv_tims1.
L043:SELECT-OPTIONS s_tims1 FOR gv_tims1.
L044:*
L045:DATA gv_tims2 TYPE tims.
L046:TYPES gtrt_tims2 LIKE RANGE OF gv_tims2.
L047:SELECT-OPTIONS s_tims2 FOR gv_tims2.
L048:
L049:*-----------------------------------------------------------------------
L050:* 主処理
L051:*-----------------------------------------------------------------------
L052:START-OF-SELECTION.
L053:  PERFORM start_of_selection
L054:    USING
L055:      s_char1
L056:      s_char2

L057:      s_numc1
L058:      s_numc2

L059:      s_dats1
L060:      s_dats2

L061:      s_tims1
L062:      s_tims2

L063:    CHANGING
L064:      gv_subrc.
L065:
L066:*-----------------------------------------------------------------------
L067:* サブルーチン
L068:*-----------------------------------------------------------------------
L069:FORM start_of_selection
L070:    USING
L071:      urt_char1 TYPE gtrt_char1
L072:      urt_char2 TYPE gtrt_char2
L073:      urt_numc1 TYPE gtrt_numc1
L074:      urt_numc2 TYPE gtrt_numc2
L075:      urt_dats1 TYPE gtrt_dats1
L076:      urt_dats2 TYPE gtrt_dats2
L077:      urt_tims1 TYPE gtrt_tims1
L078:      urt_tims2 TYPE gtrt_tims2
L079:    CHANGING
L080:      cv_subrc TYPE sy-subrc.
L081:*-----------------------------------------------------------------------
L082:* ここに、SQL文を書いてね☆
L083:* 格納する内部テーブルは、lt_dataにしてね☆
L084:* lt_dataをインライン定義すると、楽ちんだ☆
L085:  SELECT
L086:      CONCAT( CONCAT( ti0~ebeln,'-' ),ti0~ebelp ) AS c1,
L087:      CASE
L088:        WHEN ti0~werks = @space AND ti0~lgort = @space THEN @space
L089:        WHEN ti0~werks <> @space AND ti0~lgort = @space THEN ti0~werks
L090:        WHEN ti0~werks = @space AND ti0~lgort <> @space THEN CONCAT( '     ', ti0~werks )
L091:        ELSE CONCAT( CONCAT( ti0~werks,'-' ),ti0~lgort ) END AS c2,
L092:      ti0~werks,
L093:      ti0~lgort
L094:    FROM ekpo AS ti0
L095:    ORDER BY
L096:      ti0~ebeln,
L097:      ti0~ebelp
L098:    INTO TABLE @DATA(lt_data).
L099:*-----------------------------------------------------------------------
L100:  TRY.
L101:      cl_salv_table=>factory(
L102:        IMPORTING
L103:          r_salv_table = DATA(lo_alv)
L104:        CHANGING
L105:          t_table  = lt_data ).
L106:    CATCH cx_salv_msg INTO DATA(lx_salv_msg).
L107:      cv_subrc = 8.
L108:      RETURN.
L109:  ENDTRY.
L110:  DATA(lo_functions) = lo_alv->get_functions( ).
L111:  lo_functions->set_all( ).
L112:  DATA(lo_selections) = lo_alv->get_selections( ).
L113:  lo_selections->set_selection_mode(
L114:  EXPORTING
L115:  value = if_salv_c_selection_mode=>multiple ).
L116:  lo_alv->display( ).
L117:
L118:  cv_subrc = 0.
L119:ENDFORM.


(2)はあるのかな(笑)


検索キーワード
ABAP
ABAP 7.5
ABAP 7.50
SQL
Open SQL
New Open SQL
SAP HANA
Code to Data
Code Pushdown
CASE文
SQL関数
CONCAT()

以上

ABAP New open SQL:SQL関数拡張 on ABAP 7.50

ひょんなことから、ABAP 7.50を触る機会がありました。
目的は別に有ったのですが、New Open SQLを試さずにはいられませんでした。

SAPのアナウンス通り、UNIONをサポートしていたのですが、(ネタとしては派手ですね)
地味にインパクトがあるのはSQL関数拡張と思います。

Google等で以下キーワードで検索すると出てきます。
Open SQL in Release 7.50
そのなかに、SQL関数拡張「SQL Functions Expanded」があります。

ABAP 7.4の時は、New Open SQLの文字列編集系SQL関数は一つも無かったのですが、
ABAP 7.5になって、以下SQL関数が使えるようになりました。(検証してないけれど)
・CONCAT()
  文字列結合
  たとえば、DATSとTIMSを結合してTIMESTAMPに変換出来る。
・LPAD()
  文字列の桁埋め
  たとえば、0で桁埋めすれば、NUMCの内部形式に変換出来る。
・LENGTH()
  文字列の長さ取得
  たとえば、SUBSTRING等と組み合わせて。
・LTRIM()
  文字列のトリム
・REPLACE()
  文字列の置換
・RIGHT()
  文字列の切出し
・RTRIM()
  文字列のトリム
・SUBSTRING()
  文字列の切出し

Excel関数をほんの少しかじったことがあれば、フィーリングで使いこなせるものばかりです。
が、とっても適用範囲が広いので、SELECT文で内部テーブルにデータ取得後のループによる編集が、
大幅に削減できます。


ABAP CDS Viewなんかもありますが、ABAPのみで出来ることはまだまだありますね。
本当にパフォーマンスが欲しいときは、HANA Infomation View + AMDPで実装することになりますね。


あとは、内部テーブルに対してSELECT文が実行できれば、
HANA Viewと(機能的に)同等レヴェルのCode to Dataが実現できるんだけれど、
仕組み上難しいかな。
ABAP 7.52で出来るようになりました。後日改めて書きます。(2018-10-23)


検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
Open SQL
New Open SQL
Classic Open SQL
SAP HANA
HANA VIew
CDS View
ABAP CDS View
Code to Data
Code Pushdown
SQL Functions Expanded

以上

SAP HANA 備忘

SAP HANA関連を少し書こうと思う。(あらびきです。最新は違うかもしれない)

SAP HANAを語るうえで、エンジンの存在があります。
A : Join Engine
 マスタテーブル同士を表結合する。(Join)
B : OLAP Engine
 トランザクションテーブルを集計する。(Group by)
 トランザクションテーブルとマスタテーブル群を表結合する。(Join)
C : Calculation Engine
 こまいいろいろ。Union含むJoinやCaseなど...
D : SQL Engine
 スクリプトベースのSQL

そして、OLAP Engineに汗をかかせると、SAP HANAは無理なく軽やかに動作する。
厳密ではないけれど、だいたい以下Viewが各エンジンに対応する。

SAP HANA SPS10くらいまで、
 HANA information View:HANAユーザで動作
 A : Attribuite View
 B : Analytic View
 C : Calculation View

SAP HANA SPS10〜12およびSAP HANA2
 HANA information View:HANAユーザで動作
 A ; Calculation View - Dimmension
 B : Calculation View - Cube - Star join:on
 C : Calculation View - Cube - Star join:off

ABAP CDS View:Netweaver(ABAP)7.4以降:SAPユーザで動作
(少々乱暴です。実際はSQLエンジンで動作)
 A : Basic View
 B : Composite View
 C : Consumption View

ちなみに、処理速度は、HANA information Viewがもっとも高速で、
Open SQL(ABAPエディタで書くやつ)とABAP CDSはほぼ同じ(誤差の範囲)です。
恐らくですが、営業的な都合でABAP CDS万能論が出ているようです。
実際、99%以上はOpen SQLまたはABAP CDSで事足りますが、
処理速度のみを追求するとHANA information View一択になると思います。
10億レコードの集計とか...上手に作ると十数秒で戻ってきました。(爆)

少し毒を吐きます。
上記内容は、眉間にしわを寄せて(笑)語るといいかも。
なんかね、どんな技術で実装しても、本質的な部分では変わらないのに、
SAP HANAで実装すると、アカデミックになり、
Microsoft Accessで実装すると、小馬鹿にされる。
じゃぁ本質ってなんだよ。
個人的には、データの処理単位とこれに伴う設計の違いだと思っています。
ABAPや他の言語、JavaのORマッパーやdotNETのレコードセットっと言ったほうが通りが良いかな?
これら言語の一般的なプログラマーは、データセット(内部テーブル)をデータベースから取得して、
ループを回しながら、行単位で処理を記述すると思う。
しかしながら、SQL、HANA View等は、データセットを一括で処理しようとする。
(DBカーソルとかあるけれど、基本的にループを回さない)

以下書籍のコラムに、
https://www.amazon.co.jp/dp/4774173010/
SQLを設計した頭のいいお兄さんは、
行単位でループを回すような処理は行わなくても、
あらゆる機能は実装可能なんだっというような内容を主張していて、
だからSQLは、カーソルの機能は貧弱なんだとのこと。
僕も全てでは無いけれど、ほとんどの処理をループ無しに記述するように、
脳内矯正をしています。
理由というか好き嫌いなんだけれど、
SQLでデータセットを一括処理させると、
バグが発生したときに、派手な動きとして現れるので、(レコードが大量増幅したり)
見つけやすいと思う。
あと、だいたいにおいてローコストでパフォーマンスが良いと思う。


検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
Netweaver 7.4
Netweaver 7.40
Netweaver 7.5
Netweaver 7.50
Open SQL
New Open SQL
Classic Open SQL
SAP HANA
HANA VIew
CDS View
ABAP CDS View
Code to Data
Code Pushdown

以上

ABAP New open SQL:受注伝票の一括取得

少し間が空きました。

今回は、受注伝票の取得を例にしてみました。
受注伝票関連のテーブルを、明細単位でブッコヌキしてみます。

考え方としては、VBAP:明細テーブルを軸にして以下テーブル結合します。
・VBKD:納入日程行
・VBAK:ヘッダ
・VBKD:ビジネスデータ
・VBPA:取引先機能

L084:  SELECT
L085:      ti0~vbeln,
L086:      ti0~posnr,
L087:      ti0~matnr,
L088:      ti0~kwmeng,
L089:      MAX( td0~edatu ) AS edatu,
L090:      SUM( td0~bmeng ) AS bmeng,
L091:      ti2~kunnr AS kunnr_i,
L092:      th2~kunnr AS kunnr_h,
L093:      CASE
L094:        WHEN ti2~kunnr IS NOT NULL THEN ti2~kunnr
L095:        ELSE th2~kunnr END AS kunnr,
L096:      COUNT(*) AS count
L097:    FROM vbap AS ti0
L098:    LEFT OUTER JOIN vbep AS td0
L099:       ON td0~vbeln = ti0~vbeln
L100:      AND td0~posnr = ti0~posnr
L101:    LEFT OUTER JOIN vbkd AS ti1
L102:       ON ti1~vbeln = ti0~vbeln
L103:      AND ti1~posnr = ti0~posnr
L104:    LEFT OUTER JOIN vbpa AS ti2
L105:       ON ti2~vbeln = ti0~vbeln
L106:      AND ti2~posnr = ti0~posnr
L107:      AND ti2~parvw = 'WE'
L108:    INNER JOIN vbak AS th0
L109:       ON th0~vbeln = ti0~vbeln
L110:    LEFT OUTER JOIN vbkd AS th1
L111:       ON th1~vbeln = ti0~vbeln
L112:      AND th1~posnr = '000000'
L113:    LEFT OUTER JOIN vbpa AS th2
L114:       ON th2~vbeln = ti0~vbeln
L115:      AND th2~posnr = '000000'
L116:      AND th2~parvw = 'WE'
L117:    GROUP BY
L118:      ti0~vbeln,
L119:      ti0~posnr,
L120:      ti0~matnr,
L121:      ti0~kwmeng,
L122:      ti2~kunnr,
L123:      th2~kunnr
L124:    ORDER BY
L125:      ti0~vbeln,
L126:      ti0~posnr
L127:    INTO TABLE @DATA(lt_data).

ポイントは3点

VBKD:ビジネスデータおよびVBPA:取引先機能については、
ヘッダレコードと明細レコードが混在しているので、
それぞれについて2回テーブル結合しています。
L101、L110、L104、L113

明細データを優先するため、
CASE文を使用して明細データの有無(NULL値の確認)を確認して、
存在したら明細データを出力し、存在しなかったらヘッダデータを出力するようにしています。
ビジネスデータについては今回未出力としていますが、同様の記述が可能です。
L093〜L095

納入日程行の確認数量の合計値を取得するために、SUM関数を使用しています。
納入日付については、MAX関数を用いて最大値を取得しています。
L089、L090


少しプログラムを改変しました。(20171018)
L001:*&---------------------------------------------------------------------*
L002:*& Report Y_SQL_CONSOLE
L003:*&---------------------------------------------------------------------*
L004:*&
L005:*&---------------------------------------------------------------------*
L006:REPORT y_sql_console.
L007:
L008:*-----------------------------------------------------------------------
L009:* グローバル変数
L010:*-----------------------------------------------------------------------
L011:DATA gv_subrc TYPE sy-subrc.
L012:
L013:*-----------------------------------------------------------------------
L014:* 選択画面
L015:*-----------------------------------------------------------------------
L016:DATA gv_char1 TYPE char10.
L017:TYPES gtrt_char1 LIKE RANGE OF gv_char1.
L018:SELECT-OPTIONS s_char1 FOR gv_char1.
L019:
L020:DATA gv_char2 TYPE char10.
L021:TYPES gtrt_char2 LIKE RANGE OF gv_char2.
L022:SELECT-OPTIONS s_char2 FOR gv_char2.
L023:
L024:DATA gv_numc1 TYPE numc08.
L025:TYPES gtrt_numc1 LIKE RANGE OF gv_numc1.
L026:SELECT-OPTIONS s_numc1 FOR gv_numc1.
L027:
L028:DATA gv_numc2 TYPE numc08.
L029:TYPES gtrt_numc2 LIKE RANGE OF gv_numc2.
L030:SELECT-OPTIONS s_numc2 FOR gv_numc2.
L031:
L032:DATA gv_dats1 TYPE dats.
L033:TYPES gtrt_dats1 LIKE RANGE OF gv_dats1.
L034:SELECT-OPTIONS s_dats1 FOR gv_dats1.
L035:
L036:DATA gv_dats2 TYPE dats.
L037:TYPES gtrt_dats2 LIKE RANGE OF gv_dats2.
L038:SELECT-OPTIONS s_dats2 FOR gv_dats2.
L039:
L040:DATA gv_tims1 TYPE tims.
L041:TYPES gtrt_tims1 LIKE RANGE OF gv_tims1.
L042:SELECT-OPTIONS s_tims1 FOR gv_tims1.
L043:
L044:DATA gv_tims2 TYPE tims.
L045:TYPES gtrt_tims2 LIKE RANGE OF gv_tims2.
L046:SELECT-OPTIONS s_tims2 FOR gv_tims2.
L047:
L048:*-----------------------------------------------------------------------
L049:* 主処理
L050:*-----------------------------------------------------------------------
L051:START-OF-SELECTION.
L052:  PERFORM start_of_selection
L053:    USING
L054:      s_char1
L055:      s_char2

L056:      s_numc1
L057:      s_numc2

L058:      s_dats1
L059:      s_dats2

L060:      s_tims1
L061:      s_tims2

L062:    CHANGING
L063:      gv_subrc.
L064:
L065:*-----------------------------------------------------------------------
L066:* サブルーチン
L067:*-----------------------------------------------------------------------
L068:FORM start_of_selection
L069:    USING
L070:      urt_char1 TYPE gtrt_char1
L071:      urt_char2 TYPE gtrt_char2
L072:      urt_numc1 TYPE gtrt_numc1
L073:      urt_numc2 TYPE gtrt_numc2
L074:      urt_dats1 TYPE gtrt_dats1
L075:      urt_dats2 TYPE gtrt_dats2
L076:      urt_tims1 TYPE gtrt_tims1
L077:      urt_tims2 TYPE gtrt_tims2
L078:    CHANGING
L079:      cv_subrc TYPE sy-subrc.
L080:*-----------------------------------------------------------------------
L081:* ここに、SQL文を書いてね☆
L082:* 格納する内部テーブルは、lt_dataにしてね☆
L083:* lt_dataをインライン定義すると、楽ちんだ☆
L084:  SELECT
L085:      ti0~vbeln,
L086:      ti0~posnr,
L087:      ti0~matnr,
L088:      ti0~kwmeng,
L089:      MAX( td0~edatu ) AS edatu,
L090:      SUM( td0~bmeng ) AS bmeng,
L091:      ti2~kunnr AS kunnr_i,
L092:      th2~kunnr AS kunnr_h,
L093:      CASE
L094:        WHEN ti2~kunnr IS NOT NULL THEN ti2~kunnr
L095:        ELSE th2~kunnr END AS kunnr,
L096:      COUNT(*) AS count
L097:    FROM vbap AS ti0
L098:    LEFT OUTER JOIN vbep AS td0
L099:       ON td0~vbeln = ti0~vbeln
L100:      AND td0~posnr = ti0~posnr
L101:    LEFT OUTER JOIN vbkd AS ti1
L102:       ON ti1~vbeln = ti0~vbeln
L103:      AND ti1~posnr = ti0~posnr
L104:    LEFT OUTER JOIN vbpa AS ti2
L105:       ON ti2~vbeln = ti0~vbeln
L106:      AND ti2~posnr = ti0~posnr
L107:      AND ti2~parvw = 'WE'
L108:    INNER JOIN vbak AS th0
L109:       ON th0~vbeln = ti0~vbeln
L110:    LEFT OUTER JOIN vbkd AS th1
L111:       ON th1~vbeln = ti0~vbeln
L112:      AND th1~posnr = '000000'
L113:    LEFT OUTER JOIN vbpa AS th2
L114:       ON th2~vbeln = ti0~vbeln
L115:      AND th2~posnr = '000000'
L116:      AND th2~parvw = 'WE'
L117:    GROUP BY
L118:      ti0~vbeln,
L119:      ti0~posnr,
L120:      ti0~matnr,
L121:      ti0~kwmeng,
L122:      ti2~kunnr,
L123:      th2~kunnr
L124:    ORDER BY
L125:      ti0~vbeln,
L126:      ti0~posnr
L127:    INTO TABLE @DATA(lt_data).
L128:*-----------------------------------------------------------------------
L129:  TRY.
L130:      cl_salv_table=>factory(
L131:        IMPORTING
L132:          r_salv_table = DATA(lo_alv)
L133:        CHANGING
L134:          t_table  = lt_data ).
L135:    CATCH cx_salv_msg INTO DATA(lx_salv_msg).
L136:      cv_subrc = 8.
L137:      RETURN.
L138:  ENDTRY.
L139:  DATA(lo_functions) = lo_alv->get_functions( ).
L140:  lo_functions->set_all( ).
L141:  DATA(lo_selections) = lo_alv->get_selections( ).
L142:  lo_selections->set_selection_mode(
L143:  EXPORTING
L144:  value = if_salv_c_selection_mode=>multiple ).
L145:  lo_alv->display( ).
L146:
L147:  cv_subrc = 0.
L148:ENDFORM.


検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
SQL
Open SQL
New Open SQL
Classic Open SQL
SAP HANA
Code to Data
Code Pushdown
INNER JOIN
LEFT OUTER JOIN
外部結合
自己結合
IS NULL
CASE文
GROUP BY
集合関数
SUM()
MAX()

以上

ABAP New open SQL:CDHDR:変更文書ヘッダを使ってデータを取得する

今日は、CDHDR:変更文書ヘッダを利用して、xxxx年xx月xx日 xx時xx分xx秒以降に登録・変更があった
購買発注伝票のデータを取得します。
サブクエリはあまりなじみがないと思いますが、ちょっと書いてみました。
サブクエリ自体は、ABAP7.3以前からあるので、今回のSELECT文はClassic Open SQLでも記述可能です。
一般的には、CDHDR:変更文書ヘッダより、対象の購買伝票番号を取得して、一旦内部テーブルに格納して、
for all entriesで取得したりするんだと思うけれど、
ABAP出身者としてはfor all entriesがどうにも好きになれなくて、、、
内部的には、for all entries行分のSELECT文を発行して、UNIONで繋げているそうなので、
パフォーマンス的にあまり褒められた方法ではないようです。
コードとしても、SELECT文を実行する直前で、
for all entriesの内部テーブルのデータ有無をチェックする必要があったり、
美意識の問題なんだと思うんだけれど、業務ロジックとは無関係のコードを書くのが気が進まないです。
あと、New Open SQLで、for all entriesは廃止になりました。
(ABAP7.4でもClassic Open SQLで書けばいいんだけれどね)

L084:  SELECT
L085:      t0~*,
L086:      t1~*
L087:    FROM ekpo AS t0
L088:    INNER JOIN ekko AS t1
L089:       ON t1~ebeln = t0~ebeln
L090:    WHERE EXISTS (
L091:      SELECT * FROM cdhdr AS t2
L092:        WHERE t2~objectclas = 'EINKBELEG'
L093:          AND ( t2~udate > '20170101'
L094:           OR ( t2~udate = '20170101'
L095:          AND t2~utime >= '101030' ) )
L096:          AND t2~objectid = t0~ebeln )
L097:    ORDER BY
L098:      t0~ebeln,
L099:      t0~ebelp
L100:    INTO TABLE @DATA(lt_data).

結合条件は、L089、L096です。
L091~L096のサブクエリは集合関数も使えるので、
MAX()等を上手に使えば、最後に更新した日付時刻なんかも、一発で取得できます。
あと、L097~L099のソートですが、ソートテーブルより速いです。(多分、Non HANAであっても)

少しプログラムを改変しました。(20171018)

L001:*&---------------------------------------------------------------------*
L002:*& Report Y_SQL_CONSOLE
L003:*&---------------------------------------------------------------------*
L004:*&
L005:*&---------------------------------------------------------------------*
L006:REPORT y_sql_console.
L007:
L008:*-----------------------------------------------------------------------
L009:* グローバル変数
L010:*-----------------------------------------------------------------------
L011:DATA gv_subrc TYPE sy-subrc.
L012:
L013:*-----------------------------------------------------------------------
L014:* 選択画面
L015:*-----------------------------------------------------------------------
L016:DATA gv_char1 TYPE char10.
L017:TYPES gtrt_char1 LIKE RANGE OF gv_char1.
L018:SELECT-OPTIONS s_char1 FOR gv_char1.
L019:
L020:DATA gv_char2 TYPE char10.
L021:TYPES gtrt_char2 LIKE RANGE OF gv_char2.
L022:SELECT-OPTIONS s_char2 FOR gv_char2.
L023:
L024:DATA gv_numc1 TYPE numc08.
L025:TYPES gtrt_numc1 LIKE RANGE OF gv_numc1.
L026:SELECT-OPTIONS s_numc1 FOR gv_numc1.
L027:
L028:DATA gv_numc2 TYPE numc08.
L029:TYPES gtrt_numc2 LIKE RANGE OF gv_numc2.
L030:SELECT-OPTIONS s_numc2 FOR gv_numc2.
L031:
L032:DATA gv_dats1 TYPE dats.
L033:TYPES gtrt_dats1 LIKE RANGE OF gv_dats1.
L034:SELECT-OPTIONS s_dats1 FOR gv_dats1.
L035:
L036:DATA gv_dats2 TYPE dats.
L037:TYPES gtrt_dats2 LIKE RANGE OF gv_dats2.
L038:SELECT-OPTIONS s_dats2 FOR gv_dats2.
L039:
L040:DATA gv_tims1 TYPE tims.
L041:TYPES gtrt_tims1 LIKE RANGE OF gv_tims1.
L042:SELECT-OPTIONS s_tims1 FOR gv_tims1.
L043:
L044:DATA gv_tims2 TYPE tims.
L045:TYPES gtrt_tims2 LIKE RANGE OF gv_tims2.
L046:SELECT-OPTIONS s_tims2 FOR gv_tims2.
L047:
L048:*-----------------------------------------------------------------------
L049:* 主処理
L050:*-----------------------------------------------------------------------
L051:START-OF-SELECTION.
L052:  PERFORM start_of_selection
L053:    USING
L054:      s_char1
L055:      s_char2
L056:      s_numc1
L057:      s_numc2
L058:      s_dats1
L059:      s_dats2
L060:      s_tims1
L061:      s_tims2
L062:    CHANGING
L063:      gv_subrc.
L064:
L065:*-----------------------------------------------------------------------
L066:* サブルーチン
L067:*-----------------------------------------------------------------------
L068:FORM start_of_selection
L069:    USING
L070:      urt_char1 TYPE gtrt_char1
L071:      urt_char2 TYPE gtrt_char2
L072:      urt_numc1 TYPE gtrt_numc1
L073:      urt_numc2 TYPE gtrt_numc2
L074:      urt_dats1 TYPE gtrt_dats1
L075:      urt_dats2 TYPE gtrt_dats2
L076:      urt_tims1 TYPE gtrt_tims1
L077:      urt_tims2 TYPE gtrt_tims2
L078:    CHANGING
L079:      cv_subrc TYPE sy-subrc.
L080:*-----------------------------------------------------------------------
L081:* ここに、SQL文を書いてね☆
L082:* 格納する内部テーブルは、lt_dataにしてね☆
L083:* lt_dataをインライン定義すると、楽ちんだ☆
L084:  SELECT
L085:      t0~*,
L086:      t1~*
L087:    FROM ekpo AS t0
L088:    INNER JOIN ekko AS t1
L089:       ON t1~ebeln = t0~ebeln
L090:    WHERE EXISTS (
L091:      SELECT * FROM cdhdr AS t2
L092:        WHERE t2~objectclas = 'EINKBELEG'
L093:          AND ( t2~udate > '20170101'
L094:           OR ( t2~udate = '20170101'
L095:          AND t2~utime >= '101030' ) )
L096:          AND t2~objectid = t0~ebeln )
L097:    ORDER BY
L098:      t0~ebeln,
L099:      t0~ebelp
L100:    INTO TABLE @DATA(lt_data).
L101:*-----------------------------------------------------------------------
L102:  TRY.
L103:      cl_salv_table=>factory(
L104:        IMPORTING
L105:          r_salv_table = DATA(lo_alv)
L106:        CHANGING
L107:          t_table  = lt_data ).
L108:    CATCH cx_salv_msg INTO DATA(lx_salv_msg).
L109:      cv_subrc = 8.
L110:      RETURN.
L111:  ENDTRY.
L112:  DATA(lo_functions) = lo_alv->get_functions( ).
L113:  lo_functions->set_all( ).
L114:  DATA(lo_selections) = lo_alv->get_selections( ).
L115:  lo_selections->set_selection_mode(
L116:  EXPORTING
L117:  value = if_salv_c_selection_mode=>multiple ).
L118:  lo_alv->display( ).
L119:
L120:  cv_subrc = 0.
L121:ENDFORM.

検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
SQL
Open SQL
New Open SQL
Classic Open SQL
SAP HANA
Code to Data
Code Pushdown
INNER JOIN
サブクエリ
EXISTS句
集合関数

以上

ABAP New open SQL:少し複雑なテーブル結合をしてみる

今回は、従来(ABAP 7.3以前)では有効化エラーとなってしまうけれど、
New open SQLだから書ける!という類のテーブル結合を書いてみます。
BSEGテーブルに、勘定科目の名称を付加する。

  SELECT
      t0~bukrs,
      t0~belnr,
      t0~gjahr,
      t0~buzei,
      t0~shkzg,
      t0~dmbtr,
      t2~waers AS waers_d,
      t0~wrbtr,
      t1~waers,
      t0~hkont,
      t3~txt20
    FROM bseg AS t0
    INNER JOIN bkpf AS t1
       ON t1~bukrs = t0~bukrs
      AND t1~belnr = t0~belnr
      AND t1~gjahr = t0~gjahr
    INNER JOIN t001 AS t2
       ON t2~bukrs = t0~bukrs
    INNER JOIN skat AS t3 "注目
       ON t3~ktopl = t2~ktopl "注目
      AND t3~saknr = t0~hkont "注目
      AND t3~spras = @sy-langu
    ORDER BY
      t0~bukrs,
      t0~belnr,
      t0~gjahr,
      t0~buzei
    INTO TABLE @DATA(lt_data).

注目すべきは、
SKAT:勘定コード表: テキストとT001:会社コードの結合条件と
SKAT:勘定コード表: テキストとBSEG:会計伝票明細の結合条件
つまり、3つのテーブルにまたがる結合条件を記述しているのです。
これを、従来からある(Classic) Open SQLで書くと有効化時にエラーが発生します。


少しプログラムを改変しました。(20171018)

*&---------------------------------------------------------------------*
*& Report Y_SQL_CONSOLE
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT y_sql_console.

*-----------------------------------------------------------------------
* グローバル変数
*-----------------------------------------------------------------------
DATA gv_subrc TYPE sy-subrc.

*-----------------------------------------------------------------------
* 選択画面
*-----------------------------------------------------------------------
DATA gv_char1 TYPE char10.
TYPES gtrt_char1 LIKE RANGE OF gv_char1.
SELECT-OPTIONS s_char1 FOR gv_char1.

DATA gv_char2 TYPE char10.
TYPES gtrt_char2 LIKE RANGE OF gv_char2.
SELECT-OPTIONS s_char2 FOR gv_char2.

DATA gv_numc1 TYPE numc08.
TYPES gtrt_numc1 LIKE RANGE OF gv_numc1.
SELECT-OPTIONS s_numc1 FOR gv_numc1.

DATA gv_numc2 TYPE numc08.
TYPES gtrt_numc2 LIKE RANGE OF gv_numc2.
SELECT-OPTIONS s_numc2 FOR gv_numc2.

DATA gv_dats1 TYPE dats.
TYPES gtrt_dats1 LIKE RANGE OF gv_dats1.
SELECT-OPTIONS s_dats1 FOR gv_dats1.

DATA gv_dats2 TYPE dats.
TYPES gtrt_dats2 LIKE RANGE OF gv_dats2.
SELECT-OPTIONS s_dats2 FOR gv_dats2.

DATA gv_tims1 TYPE tims.
TYPES gtrt_tims1 LIKE RANGE OF gv_tims1.
SELECT-OPTIONS s_tims1 FOR gv_tims1.

DATA gv_tims2 TYPE tims.
TYPES gtrt_tims2 LIKE RANGE OF gv_tims2.
SELECT-OPTIONS s_tims2 FOR gv_tims2.

*-----------------------------------------------------------------------
* 主処理
*-----------------------------------------------------------------------
START-OF-SELECTION.
  PERFORM start_of_selection
    USING
      s_char1
      s_char2
      s_numc1
      s_numc2
      s_dats1
      s_dats2
      s_tims1
      s_tims2
    CHANGING
      gv_subrc.

*-----------------------------------------------------------------------
* サブルーチン
*-----------------------------------------------------------------------
FORM start_of_selection
    USING
      urt_char1 TYPE gtrt_char1
      urt_char2 TYPE gtrt_char2
      urt_numc1 TYPE gtrt_numc1
      urt_numc2 TYPE gtrt_numc2
      urt_dats1 TYPE gtrt_dats1
      urt_dats2 TYPE gtrt_dats2
      urt_tims1 TYPE gtrt_tims1
      urt_tims2 TYPE gtrt_tims2
    CHANGING
      cv_subrc TYPE sy-subrc.
*-----------------------------------------------------------------------
* ここに、SQL文を書いてね☆
* 格納する内部テーブルは、lt_dataにしてね☆
* lt_dataをインライン定義すると、楽ちんだ☆
  SELECT
      t0~bukrs,
      t0~belnr,
      t0~gjahr,
      t0~buzei,
      t0~shkzg,
      t0~dmbtr,
      t2~waers AS waers_d,
      t0~wrbtr,
      t1~waers,
      t0~hkont,
      t3~txt20
    FROM bseg AS t0
    INNER JOIN bkpf AS t1
       ON t1~bukrs = t0~bukrs
      AND t1~belnr = t0~belnr
      AND t1~gjahr = t0~gjahr
    INNER JOIN t001 AS t2
       ON t2~bukrs = t0~bukrs
    INNER JOIN skat AS t3 "注目
       ON t3~ktopl = t2~ktopl "注目
      AND t3~saknr = t0~hkont "注目
      AND t3~spras = @sy-langu
    ORDER BY
      t0~bukrs,
      t0~belnr,
      t0~gjahr,
      t0~buzei
    INTO TABLE @DATA(lt_data).
*-----------------------------------------------------------------------
  TRY.
      cl_salv_table=>factory(
        IMPORTING
          r_salv_table = DATA(lo_alv)
        CHANGING
          t_table  = lt_data ).
    CATCH cx_salv_msg INTO DATA(lx_salv_msg).
      cv_subrc = 8.
      RETURN.
  ENDTRY.
  DATA(lo_functions) = lo_alv->get_functions( ).
  lo_functions->set_all( ).
  DATA(lo_selections) = lo_alv->get_selections( ).
  lo_selections->set_selection_mode(
  EXPORTING
  value = if_salv_c_selection_mode=>multiple ).
  lo_alv->display( ).

  cv_subrc = 0.
ENDFORM.


検索キーワード
ABAP
ABAP 7.4
ABAP 7.40
ABAP 7.5
ABAP 7.50
SQL
Open SQL
New Open SQL
SAP HANA
Code to Data
Code Pushdown
INNER JOIN

以上