ヘッドホン:MDR-CD900ST:ナンパ!!?されちゃいました(笑)

連日コロちゃん騒動で窮屈な日々を過ごしています。そして、エスカレータの中も窮屈で気を使いますね〜。

今朝通勤でいつも通りエスカレータに乗りました。確か私を含め5人で、私が降りる14Fと15Fが押されました。14F組は私1人でアウェーな感じ。しばらくして、、、

「900ST改造していてカッコいいですね」

と声を掛けられ、いつもの!!?声かけられ力発揮か〜☆MDR-CD900STを期待していたようだったのですが、今朝は、MDR-Z1000バランス改造済で、少し残念そうでした。

MDR-CD900STは、長いコードと6.3mmの巨大なプラグのお陰で、パンピーには敷居が高いんですねぇ〜。一方でパーツがバラで買えるので、DIYするには敷居が低いんですが、普通ヘッドホンでDIYしないよなぁ。

ブログの通りなのですが、MDR-CD900STネオジウムは、以下いわゆる魔改造していて、
・折り畳み改造
・渡り配線PCOCC8N引き直しLR独立配線
・3.5mm4極MDR-1A互換バランス対応端子
・MDR-M1ST純正イヤーパッド
・シリコン角紐によるアラウンドイヤー化
f:id:dai_h_73:20200403003126j:plain
そんなことは分からないだろうなぁと思いつつ、素直に嬉しくて「ありがとうございます」と返事して、14Fで降りました。

明日からしばらく自宅勤務になるので会社へ行かないのですが、次回会った時はもう少し込み入った会話になればなぁと
思いました☆

おんなこどもには到底理解出来ないこだわりの塊なのですが、分かる人もいないだろうと、こっそり楽しんでいるのですが、分かっちゃう人もいるんだなぁと改めて思いました。

ABAP New open SQL:RANGEテーブルの限界について

昔から語り継がれている残念な制限に、「RANGEテーブルは1,000レコード以下を目安にすること」があると思います。

一方で、SAP HANAのドキュメントの「System Limitations」→「Length of an SQL statement」を参照すると、「2,147,483,648 Bytes」つまり、2GBとあります。
これは、単一のSQL文の文字数制限を意味しています。ちなみに、Oracleは64KBだったと思います。

話を戻して、ABAP独自のRANGEテーブルという仕組みは、Net WeaverがWhere句に展開してDatabaseに投げているそうです。CL_SHDB_SELTABというクラスもありますね。
そこで、私推測してみました。RANGEテーブルの1,000レコード制限は、Where句に展開したときに、Oracleの64KBを超えてしまう恐れがあるところから始まっているのではないだろうか?そしてSAP HANAは2GBとなっているので、100万レコードオーダーでも動くのではないだろうかと。

実際やってみました。
プログラムは以下の通りです。
・ACDOCAまたは、EKPOより、キー項目(一部)を取得して、RANGEテーブルに格納します。
・WHERE句にRANGEテーブルを設定して、結果セットを取得します。

自身が触れる環境の都合で、純粋な比較は出来ませんでしたが以下の通りになりました。

ABAP 7.31 & Oracle10.2:P-1:EKPOで測定
OK:9,998レコード
NG:9,999レコード

ABAP 7.52 & SAP HANA:P-1: EKPOで測定
OK:30,000レコード
NG:データが無いため測定不可

ABAP 7.52 & SAP HANA:P-2: ACDOCAで測定
OK:32,757レコード
NG:32.758レコード

REPORT Y_SQL_CONSOLE.

*-----------------------------------------------------------------------
* グローバル変数
*-----------------------------------------------------------------------
DATA GDF_SUBRC TYPE SY-SUBRC.

*-----------------------------------------------------------------------
* 選択画面
*-----------------------------------------------------------------------
DATA GDF_CHAR1 TYPE CHAR30.
TYPES GTR_CHAR1 LIKE RANGE OF GDF_CHAR1.
SELECT-OPTIONS S_CHAR1 FOR GDF_CHAR1.

DATA GDF_CHAR2 TYPE CHAR30.
TYPES GTR_CHAR2 LIKE RANGE OF GDF_CHAR2.
SELECT-OPTIONS S_CHAR2 FOR GDF_CHAR2.

DATA GDF_NUMC1 TYPE NUMC08.
TYPES GTR_NUMC1 LIKE RANGE OF GDF_NUMC1.
SELECT-OPTIONS S_NUMC1 FOR GDF_NUMC1.

DATA GDF_NUMC2 TYPE NUMC08.
TYPES GTR_NUMC2 LIKE RANGE OF GDF_NUMC2.
SELECT-OPTIONS S_NUMC2 FOR GDF_NUMC2.

DATA GDF_DATS1 TYPE DATS.
TYPES GTR_DATS1 LIKE RANGE OF GDF_DATS1.
SELECT-OPTIONS S_DATS1 FOR GDF_DATS1.

DATA GDF_DATS2 TYPE DATS.
TYPES GTR_DATS2 LIKE RANGE OF GDF_DATS2.
SELECT-OPTIONS S_DATS2 FOR GDF_DATS2.

DATA GDF_TIMS1 TYPE TIMS.
TYPES GTR_TIMS1 LIKE RANGE OF GDF_TIMS1.
SELECT-OPTIONS S_TIMS1 FOR GDF_TIMS1.

DATA GDF_TIMS2 TYPE TIMS.
TYPES GTR_TIMS2 LIKE RANGE OF GDF_TIMS2.
SELECT-OPTIONS S_TIMS2 FOR GDF_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
      GDF_SUBRC.

*-----------------------------------------------------------------------
* サブルーチン
*-----------------------------------------------------------------------
FORM START_OF_SELECTION
    USING
      PUR_CHAR1 TYPE GTR_CHAR1
      PUR_CHAR2 TYPE GTR_CHAR2
      PUR_NUMC1 TYPE GTR_NUMC1
      PUR_NUMC2 TYPE GTR_NUMC2
      PUR_DATS1 TYPE GTR_DATS1
      PUR_DATS2 TYPE GTR_DATS2
      PUR_TIMS1 TYPE GTR_TIMS1
      PUR_TIMS2 TYPE GTR_TIMS2
    CHANGING
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
*-----------------------------------------------------------------------
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆

  "P-1
  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE EKPO-BUKRS,
      COUNT  TYPE I,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.

  DATA:
    LDR_KEY  LIKE RANGE OF EKPO-EBELN,
    LDT_DATA TYPE LTT_DATA.
  FIELD-SYMBOLS:
    <LFS_KEY> LIKE LINE OF LDR_KEY.

  SELECT
      EKPO~EBELN AS LOW
    INTO CORRESPONDING FIELDS OF TABLE LDR_KEY
    UP TO 9998 ROWS
    FROM EKPO
    GROUP BY
      EKPO~EBELN
    ORDER BY
      EKPO~EBELN.
  LOOP AT LDR_KEY ASSIGNING <LFS_KEY>.
    <LFS_KEY>-SIGN = 'I'.
    <LFS_KEY>-OPTION = 'EQ'.
  ENDLOOP.

  TRY .
      SELECT
          EKPO~BUKRS
          COUNT( * ) AS COUNT
        INTO TABLE LDT_DATA
        FROM EKPO
        WHERE EKPO~EBELN IN LDR_KEY
        GROUP BY
          EKPO~BUKRS
        ORDER BY
          EKPO~BUKRS.
    CATCH CX_SY_OPEN_SQL_DB.


      POF_SUBRC = 8.
      RETURN.
  ENDTRY.
*
*  "P-2
*  TYPES:
*    BEGIN OF LTS_DATA,
*      RBUKRS TYPE ACDOCA-RBUKRS,
*      COUNT  TYPE I,
*    END OF LTS_DATA,
*    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
*
*  DATA:
*    LDR_KEY  LIKE RANGE OF ACDOCA-BELNR,
*    LDT_DATA TYPE LTT_DATA.
*  FIELD-SYMBOLS:
*    <LFS_KEY> LIKE LINE OF LDR_KEY.
*
*  SELECT
*      ACDOCA~BELNR AS LOW
*    INTO CORRESPONDING FIELDS OF TABLE LDR_KEY
*    UP TO 32757 ROWS
*    FROM ACDOCA
*    GROUP BY
*      ACDOCA~BELNR
*    ORDER BY
*      ACDOCA~BELNR.
*  LOOP AT LDR_KEY ASSIGNING <LFS_KEY>.
*    <LFS_KEY>-SIGN = 'I'.
*    <LFS_KEY>-OPTION = 'EQ'.
*  ENDLOOP.
*
*  TRY .
*      SELECT
*          ACDOCA~RBUKRS
*          COUNT( * ) AS COUNT
*        INTO TABLE LDT_DATA
*        FROM ACDOCA
*        WHERE ACDOCA~BELNR IN LDR_KEY
*        GROUP BY
*          ACDOCA~RBUKRS
*        ORDER BY
*          ACDOCA~RBUKRS.
*    CATCH CX_SY_OPEN_SQL_DB.
*      POF_SUBRC = 8.
*      RETURN.
*  ENDTRY.

*-----------------------------------------------------------------------
  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
*-----------------------------------------------------------------------

  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE  = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.
  DATA LDO_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS_LIST.
  LDO_FUNCTIONS = LDO_ALV->GET_FUNCTIONS( ).
  LDO_FUNCTIONS->SET_ALL( ).
  DATA LDO_SELECTIONS TYPE REF TO CL_SALV_SELECTIONS.
  LDO_SELECTIONS = LDO_ALV->GET_SELECTIONS( ).
  LDO_SELECTIONS->SET_SELECTION_MODE(
  EXPORTING
  VALUE = IF_SALV_C_SELECTION_MODE=>MULTIPLE ).

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.

  DATA LDO_H_LABEL TYPE REF TO CL_SALV_FORM_LABEL.
  LDO_H_LABEL = LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 ).
  LDO_H_LABEL->SET_TEXT( 'パフォーマンスデータ' ).

  DATA LDO_H_FLOW TYPE REF TO CL_SALV_FORM_LAYOUT_FLOW.

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 2  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'タイムスタンプ(UTC)データ取得開始' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 2  COLUMN = 2 ).
  DATA LDF_UTC_START TYPE CHAR30.
  WRITE LDF_TIMESTAMP_START TIME ZONE SY-ZONLO TO LDF_UTC_START.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_UTC_START ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 3  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'タイムスタンプ(UTC)データ取得終了' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 3  COLUMN = 2 ).
  DATA LDF_UTC_END TYPE CHAR30.
  WRITE LDF_TIMESTAMP_END TIME ZONE SY-ZONLO TO LDF_UTC_END.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_UTC_END ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 4  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'タイムスタンプ(UTC)終了と開始の差' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 4  COLUMN = 2 ).
  DATA LDF_TIMESTAMP_SA TYPE TIMESTAMPL.
  LDF_TIMESTAMP_SA = CL_ABAP_TSTMP=>SUBTRACT(
      TSTMP1 = LDF_TIMESTAMP_END
      TSTMP2 = LDF_TIMESTAMP_START ).
  DATA LDF_SA TYPE CHAR30.
  WRITE LDF_TIMESTAMP_SA TIME ZONE SY-ZONLO TO LDF_SA.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_TIMESTAMP_SA ).

  DATA LDF_COUNT TYPE INT4.
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 5  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = '入力件数' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 5  COLUMN = 2 ).
  SELECT COUNT(*) FROM EKPO INTO LDF_COUNT.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_COUNT ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 6  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = '出力件数' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 6  COLUMN = 2 ).
  DESCRIBE TABLE LDT_DATA LINES LDF_COUNT.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_COUNT ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.                    "START_OF_SELECTION

検索キーワード
ABAP
ABAP 7.31
ABAP 7.4
ABAP 7.50
ABAP 7.51
ABAP 7.52
SQL
Open SQL
New Open SQL
Classic Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP ERP 6.0
SAP S/4HANA
レンジテーブル
RANGE TABLE

ヘッドホン:サマリウムコバルト3兄弟 バランス化

勝手に以下をサマリウムコバルト3兄弟と呼んでいます。
・MDR-CD900 民生用
・MDR-CD900 業務用
MDR-7506 サマリウムコバルト 版
物の価値基準は人それぞれなのでなんとも言えないけれど、いずれも25-35年前の機材なので希少性という意味では価値があると思います。そんなサマリウムコバルト3兄弟に手を加えるのは多少勇気が入りました。
ことの発端は、激安で入手したAKG K701のイージーなバランス化にインスパイアされて(笑)可逆性を確保しつつバランス化が可能なのではとの結論に至りました。そんなわけでバランス化しました。
手順は、以下の通りです。
・ハウジング左を開ける。
・既存のコードをハンダゴテで取り外す。
AKG K701の余りコード(約100mm)に、パネル用の4極3.5mmジャックを空中配線する。
・上記を既存コードと同様の手順でハンダ付けする。
・ハウジング左を閉じる。
逆の手順を辿れば、いつでもオリジナルに戻れます。

f:id:dai_h_73:20200227231028j:plain

f:id:dai_h_73:20200227231244j:plain

それぞれ音質に特徴がありますが、特に中学生の時からの一番のお気に入りで棚の奥にそっとしまっていたMDR-CD900民生用の稼働率が大幅に改善しました。そしてバランス駆動出来たことに、35年の時間を経て静かな感動を感じました。人生初のヘッドホンがMDR-CD900民生用で、今でもこの音が一番好きなんです。カマカマの歌を何回も聴いたよなぁ〜。音質は後ほど。

キーワード
MDR-CD900 民生用
MDR-CD900 業務用
MDR-7506 サマリウムコバルト
MDR-CD900ST
バランス
バランス化
GND分離
グランド分離
MDR-1A互換
MDR-M1ST互換

ABAP New open SQL:Code Pushdown って何のこと?(2)

ABAP New open SQL:Code Pushdown って何のこと?(2)

何となくシリーズ化しようと思い始めています。
初回は実践とは程遠い要件でしたが、2回目はもう少し実践に近い雰囲気を出してみました。
購買伝票明細一覧を取得します。
伝票番号、伝票タイプ等、組織情報等、数量、明細納入期日の最小および最大を取得します。

N-1
Non-Code Pushdown
ABAP 7.31 OK
従来の実装方法
分納契約納入日程行-明細納入期日の最大値と最小値を取得するのに、
それぞれITABに一旦データを溜め込んで、BINARY SEARCHで取得する
ソースコード:334行
とにかく実装が大変でした。また、データコピーを極力排除したので、従来の実装方法としてこれ以上軽量高速に実装する方法を私は知りません。手前味噌ですが、ほぼチャンピョンデータを叩き出していると思います。(多分)

P-1
Code Pushdown
ABAP 7.31 OK
全てのテーブルを表結合して、明細レコード単位に集約する
ソースコード:99行
今回の実装では、実質最小のコード量です。しかしながら、たまたま要件にフィットしただけの話で、毎回このような実装が取れるわけでは無いです。例えば、特定のルールで分納契約納入日程行の単一レコードを選択してデータを取り出す場合、この方法は取れません。

P-2
Code Pushdown
ABAP 7.52以降
トランザクションデータを全件取得後、
購買伝票ヘッダ、明細データと
分納契約納入日程行-明細納入期日の最大と最小を算出して、
各種マスタデータと表結合する
ソースコード:151行
私が考える、要件に対して柔軟性があり、パフォーマンスも考慮した実装です。私だったら何も指示が無ければこの方法で実装します。

P-3
Code Pushdown
ABAP 7.52以降
分納契約納入日程行-明細納入期日の最大と最小を算出して、
購買伝票ヘッダ、明細データを取得し、
各種マスタデータと表結合する
ソースコード:92行
誤りの例として、実装してみました。EKPOの全てのレコードを取得する場合は要件通り動作しますが、通常は選択画面に入力した値でフィルタすると思います。Where句を充分に効かせることが出来ないのです。少し気を抜くと詳細設計過程で仮実装してしまいます。(今回も気を抜いていました)


パフォーマンスデータ
ABAP 7.52(SAP S/4HANA)HDB環境は以下の通りとなりました。
購買伝票明細:41,000レコード→出力:41,000レコード
分納契約納入日程行は、明細1レコードに対してほぼ1レコードなので、レコード集約は僅かに行われる程度となっています。SAP HANAは集約が非常に速く、集約度合いが増すとパフォーマンス差が大きくなります。

N-1:0.69sec
P-1:0.72sec
P-2:0.45sec
P-3:0.66sec
結果としては、P-2:Code Pushdownの私が考える実装方法がトップタイムを叩き出して、一先ず安心しました。個人的に意外だったのは、N-1:Non-Code Pushdownが大健闘だったことです。BINARY SEARCHを充分に効かせて、フィールドシンボルでデータコピーを最小限にすると、データ量によっては、まだまだパフォーマンスを充分確保することが出来ると思いました。ただし、…実装するのに骨が折れそうになります。辛い…。

ABAP 7.31(ERP 6.0)Oracle10.2環境は以下の通りとなりました。
購買伝票明細:31,000レコード→出力:31,000レコード

N-1:1.55
初回は20-30秒

P-1:0.34
初回は0.8-1.0秒

何故か、この環境は初回と2回目以降で、パフォーマンス差が大きかったので、初回データも載せました。私はABAPのバッファアクセスについてよく知らないのですが、おそらく2回目以降はバッファアクセスが十分に効いているのだと思います。ただし、JOIN句を使用すると確かバッファアクセスは無効になるんでしたっけ?知識不足でごめんなさい。そうは言ってもP-1:Code Pushdownの圧勝でした。特に初回アクセスでは大差がつきました。データベースの並列実行に対するパフォーマンス悪化はあるのかもしれませんが、比較的モダンなOracle10.2です。多分しんこくなじたいにはならないのではないかとおもいます。無責任ですが…。

2023-08-14:ラジオボタンで選択できるように修正。

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

*-----------------------------------------------------------------------
* GLOBAL VARIABLE
*-----------------------------------------------------------------------
DATA:
  GDS_BAPIRET2 TYPE BAPIRET2,                     "リターンパラメータ
  GDF_SUBRC    TYPE SY-SUBRC.                     "リターンコード

*-----------------------------------------------------------------------
* CONDITION VIEW
*-----------------------------------------------------------------------

PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ
PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数
PARAMETERS:
  P_731N1 RADIOBUTTON GROUP RB1,                 "N-1:Non-Code Pushdown:ITABを活用した従来の実装方法
  P_731P1 RADIOBUTTON GROUP RB1,                 "P-1:Code Pushdown:全てのテーブルを表結合して、明細レコード単位に集約する
  P_740P2 RADIOBUTTON GROUP RB1,                 "P-2:Code Pushdown:トランザクションデータを全件取得後、ヘッダ明細、分納契約納入日程行に分けて、最後に各種マスタデータと表結合する
  P_740P3 RADIOBUTTON GROUP RB1.                 "P-3:Code Pushdown:分納契約納入日程行を取得して、ヘッダ明細を取得し、最後に各種マスタデータと表結合する

*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  CASE ABAP_TRUE.
    WHEN P_731N1.
      PERFORM START_OF_SELECTION_731N1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_731P1.
      PERFORM START_OF_SELECTION_731P1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740P2.
      PERFORM START_OF_SELECTION_740P2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740P3.
      PERFORM START_OF_SELECTION_740P3
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN OTHERS.
      LEAVE TO LIST-PROCESSING.
  ENDCASE.

*-----------------------------------------------------------------------
* SUBROUTINE
*-----------------------------------------------------------------------
FORM START_OF_SELECTION_731N1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票明細一覧を取得します。
  "伝票番号、伝票タイプ等、組織情報等、数量、明細納入期日の最小および最大を取得します。
  TYPES:
    BEGIN OF LTS_DATA,
      EBELN      TYPE EKPO-EBELN,                 "購買伝票番号
      EBELP      TYPE EKPO-EBELP,                 "購買伝票の明細番号
      BSART      TYPE EKKO-BSART,                 "購買伝票タイプ
      EKKO_LOEKZ TYPE EKKO-LOEKZ,                 "購買伝票の削除フラグ:ヘッダ
      PSTYP      TYPE EKPO-PSTYP,                 "購買伝票の明細カテゴリ
      EKPO_LOEKZ TYPE EKPO-LOEKZ,                 "購買伝票の削除フラグ:明細
      BUKRS      TYPE EKKO-BUKRS,                 "会社コード
      BUTXT      TYPE T001-BUTXT,                 "会社コードまたは会社の名称
      EKGRP      TYPE EKKO-EKGRP,                 "購買グループ
      EKNAM      TYPE T024-EKNAM,                 "購買グループテキスト
      EKORG      TYPE EKKO-EKORG,                 "購買組織
      EKOTX      TYPE T024E-EKOTX,                "購買組織テキスト
      WERKS      TYPE EKPO-WERKS,                 "プラント
      NAME1      TYPE T001W-NAME1,                "名称
      LGORT      TYPE EKPO-LGORT,                 "保管場所
      LGOBE      TYPE T001L-LGOBE,                "保管場所テキスト
      MATNR      TYPE EKPO-MATNR,                 "品目コード
      TXZ01      TYPE EKPO-TXZ01,                 "テキスト (短)
      MENGE      TYPE EKPO-MENGE,                 "購買発注量
      MEINS      TYPE EKPO-MEINS,                 "発注単位
      EINDT_MIN  TYPE EKET-EINDT,                 "明細納入期日:最小
      EINDT_MAX  TYPE EKET-EINDT,                 "明細納入期日:最大
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA,     "一覧データ


    BEGIN OF LTS_EKET,
      EBELN TYPE EKPO-EBELN,                      "購買伝票番号
      EBELP TYPE EKPO-EBELP,                      "購買伝票の明細番号
      EINDT TYPE EKET-EINDT,                      "明細納入期日
    END OF LTS_EKET,
    LTT_EKET TYPE STANDARD TABLE OF LTS_EKET,


    BEGIN OF LTS_T001,                            "会社コード
      BUKRS TYPE T001-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
    END OF LTS_T001,
    LTT_T001 TYPE STANDARD TABLE OF LTS_T001,     "会社コード

    BEGIN OF LTS_T024,                            "購買グループ
      EKGRP TYPE T024-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
    END OF LTS_T024,
    LTT_T024 TYPE STANDARD TABLE OF LTS_T024,     "購買グループ

    BEGIN OF LTS_T024E,                           "購買組織
      EKORG TYPE T024E-EKORG,                     "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
    END OF LTS_T024E,
    LTT_T024E TYPE STANDARD TABLE OF LTS_T024E,   "購買組織

    BEGIN OF LTS_T001W,                           "プラント/支店
      WERKS TYPE T001W-WERKS,                     "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
    END OF LTS_T001W,
    LTT_T001W TYPE STANDARD TABLE OF LTS_T001W,   "プラント/支店

    BEGIN OF LTS_T001L,                           "保管場所
      WERKS TYPE T001L-WERKS,                     "プラント
      LGORT TYPE T001L-LGORT,                     "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
    END OF LTS_T001L,
    LTT_T001L TYPE STANDARD TABLE OF LTS_T001L.   "保管場所

  DATA:
    LDT_DATA     TYPE LTT_DATA,                   "一覧データ
    LDT_DATA1    TYPE LTT_DATA,                   "一覧データ:作業用

    LDT_EKET_MIN TYPE LTT_EKET,                   "分納契約納入日程行:最小
    LDT_EKET_MAX TYPE LTT_EKET,                   "分納契約納入日程行:最大

    LDT_T001     TYPE LTT_T001,                   "会社コード
    LDT_T024     TYPE LTT_T024,                   "購買グループ
    LDT_T024E    TYPE LTT_T024E,                  "購買組織
    LDT_T001W    TYPE LTT_T001W,                  "プラント/支店
    LDT_T001L    TYPE LTT_T001L.                  "保管場所

  FIELD-SYMBOLS:
    <LFS_DATA>     LIKE LINE OF LDT_DATA,         "一覧データ

    <LFS_EKET_MIN> LIKE LINE OF LDT_EKET_MIN,     "分納契約納入日程行:最小
    <LFS_EKET_MAX> LIKE LINE OF LDT_EKET_MAX,     "分納契約納入日程行:最大

    <LFS_T001>     LIKE LINE OF LDT_T001,         "会社コード
    <LFS_T024>     LIKE LINE OF LDT_T024,         "購買グループ
    <LFS_T024E>    LIKE LINE OF LDT_T024E,        "購買組織
    <LFS_T001W>    LIKE LINE OF LDT_T001W,        "プラント/支店
    <LFS_T001L>    LIKE LINE OF LDT_T001L.        "保管場所

  SELECT
      EKPO~EBELN                                  "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
      EKKO~BSART                                  "購買伝票タイプ
      EKKO~LOEKZ AS EKKO_LOEKZ                    "購買伝票の削除フラグ:ヘッダ
      EKPO~PSTYP                                  "購買伝票の明細カテゴリ
      EKPO~LOEKZ AS EKPO_LOEKZ                    "購買伝票の削除フラグ:明細
      EKKO~BUKRS                                  "会社コード
      EKKO~EKGRP                                  "購買グループ
      EKKO~EKORG                                  "購買組織
      EKPO~WERKS                                  "プラント
      EKPO~LGORT                                  "保管場所
      EKPO~MATNR                                  "品目コード
      EKPO~TXZ01                                  "テキスト (短)
      EKPO~MENGE                                  "購買発注量
      EKPO~MEINS                                  "発注単位
    INTO CORRESPONDING FIELDS OF TABLE LDT_DATA
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN.                "購買伝票番号
  SORT LDT_DATA ASCENDING BY
      EBELN                                       "購買伝票番号
      EBELP.                                      "購買伝票の明細番号

  IF LDT_DATA IS NOT INITIAL.                     "一覧データ
    SELECT
        EKET~EBELN                                "購買伝票番号
        EKET~EBELP                                "購買伝票の明細番号
        EKET~EINDT                                "明細納入期日
      INTO TABLE LDT_EKET_MIN                     "分納契約納入日程行:最小
      FROM EKET                                   "分納契約納入日程行
      FOR ALL ENTRIES IN LDT_DATA                 "一覧データ
      WHERE EKET~EBELN = LDT_DATA-EBELN           "購買伝票番号
        AND EKET~EBELP = LDT_DATA-EBELP.          "購買伝票の明細番号
    IF SY-SUBRC = 0.
      LDT_EKET_MAX[] = LDT_EKET_MIN[].            "分納契約納入日程行:最大
      SORT LDT_EKET_MIN BY                        "分納契約納入日程行:最小
          EBELN ASCENDING                         "購買伝票番号
          EBELP ASCENDING                         "購買伝票の明細番号
          EINDT ASCENDING.                        "明細納入期日
      DELETE ADJACENT DUPLICATES FROM LDT_EKET_MIN COMPARING"分納契約納入日程行:最小
          EBELN                                   "購買伝票番号
          EBELP.                                  "購買伝票の明細番号
      SORT LDT_EKET_MAX BY                        "分納契約納入日程行:最大
          EBELN ASCENDING                         "購買伝票番号
          EBELP ASCENDING                         "購買伝票の明細番号
          EINDT DESCENDING.                       "明細納入期日
      DELETE ADJACENT DUPLICATES FROM LDT_EKET_MAX COMPARING"分納契約納入日程行:最大
          EBELN                                   "購買伝票番号
          EBELP.                                  "購買伝票の明細番号
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1[] = LDT_DATA[].                       "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      BUKRS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      BUKRS.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001~BUKRS                                "会社コード
        T001~BUTXT                                "会社コードまたは会社の名称
      INTO TABLE LDT_T001                         "会社コード
      FROM T001
      FOR ALL ENTRIES IN LDT_DATA1                "一覧データ:作業用
      WHERE T001~BUKRS = LDT_DATA1-BUKRS.         "会社コード
    IF SY-SUBRC = 0.
      SORT LDT_T001 ASCENDING BY                  "会社コード
          BUKRS.                                  "会社コード
      DELETE ADJACENT DUPLICATES FROM LDT_T001 COMPARING"会社コード
          BUKRS.                                  "会社コード
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1[] = LDT_DATA[].                       "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      EKGRP.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      EKGRP.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T024~EKGRP                                "購買グループ
        T024~EKNAM                                "購買グループテキスト
      INTO TABLE LDT_T024                         "購買グループ
      FROM T024                                   "購買グループ
      FOR ALL ENTRIES IN LDT_DATA1                "一覧データ:作業用
      WHERE T024~EKGRP = LDT_DATA1-EKGRP.         "購買グループ
    IF SY-SUBRC = 0.
      SORT LDT_T024 ASCENDING BY                  "購買グループ
          EKGRP.                                  "購買グループ
      DELETE ADJACENT DUPLICATES FROM LDT_T024 COMPARING"購買グループ
          EKGRP.                                  "購買グループ
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1[] = LDT_DATA[].                       "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      EKORG.                                      "購買組織
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      EKORG.                                      "購買組織
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T024E~EKORG                               "購買組織
        T024E~EKOTX                               "購買組織テキスト
      INTO TABLE LDT_T024E                        "購買組織
      FROM T024E                                  "購買組織
      FOR ALL ENTRIES IN LDT_DATA1                "一覧データ:作業用
      WHERE T024E~EKORG = LDT_DATA1-EKORG.        "購買組織
    IF SY-SUBRC = 0.
      SORT LDT_T024E ASCENDING BY                 "購買組織
          EKORG.                                  "購買組織
      DELETE ADJACENT DUPLICATES FROM LDT_T024E COMPARING"購買組織
          EKORG.                                  "購買組織
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1[] = LDT_DATA[].                       "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      WERKS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      WERKS.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001W~WERKS                               "プラント
        T001W~NAME1                               "名称
      INTO TABLE LDT_T001W                        "プラント/支店
      FROM T001W                                  "プラント/支店
      FOR ALL ENTRIES IN LDT_DATA1                "一覧データ:作業用
      WHERE T001W~WERKS = LDT_DATA1-WERKS.        "プラント
    IF SY-SUBRC = 0.
      SORT LDT_T001W ASCENDING BY                 "プラント/支店
          WERKS.                                  "プラント
      DELETE ADJACENT DUPLICATES FROM LDT_T001W COMPARING"プラント/支店
          WERKS.                                  "プラント
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1[] = LDT_DATA[].                       "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      WERKS                                       "プラント
      LGORT.                                      "保管場所
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      WERKS                                       "プラント
      LGORT.                                      "保管場所
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001L~WERKS                               "プラント
        T001L~LGORT                               "保管場所
        T001L~LGOBE                               "保管場所テキスト
      INTO TABLE LDT_T001L                        "保管場所
      FROM T001L                                  "保管場所
      FOR ALL ENTRIES IN LDT_DATA1                "一覧データ:作業用
      WHERE T001L~WERKS = LDT_DATA1-WERKS         "プラント
        AND T001L~LGORT = LDT_DATA1-LGORT.        "保管場所
    IF SY-SUBRC = 0.
      SORT LDT_T001L ASCENDING BY                 "保管場所
          WERKS                                   "プラント
          LGORT.                                  "保管場所
      DELETE ADJACENT DUPLICATES FROM LDT_T001L COMPARING
          WERKS                                   "プラント
          LGORT.                                  "保管場所
    ENDIF.
  ENDIF.

  LOOP AT LDT_DATA ASSIGNING <LFS_DATA>.          "一覧データ

    READ TABLE LDT_EKET_MIN WITH KEY              "分納契約納入日程行:最小
        EBELN = <LFS_DATA>-EBELN                  "購買伝票番号
        EBELP = <LFS_DATA>-EBELP                  "購買伝票の明細番号
      BINARY SEARCH
      ASSIGNING <LFS_EKET_MIN>.                   "分納契約納入日程行:最小
    IF SY-SUBRC = 0.
      <LFS_DATA>-EINDT_MIN = <LFS_EKET_MIN>-EINDT."明細納入期日:最小
    ENDIF.

    READ TABLE LDT_EKET_MAX                       "分納契約納入日程行:最大
      WITH KEY
        EBELN = <LFS_DATA>-EBELN                  "購買伝票番号
        EBELP = <LFS_DATA>-EBELP                  "購買伝票の明細番号
      BINARY SEARCH
      ASSIGNING <LFS_EKET_MAX>.                   "分納契約納入日程行:最大
    IF SY-SUBRC = 0.
      <LFS_DATA>-EINDT_MAX = <LFS_EKET_MAX>-EINDT."明細納入期日:最大
    ENDIF.

    READ TABLE LDT_T001 WITH KEY                  "会社コード
        BUKRS = <LFS_DATA>-BUKRS                  "会社コード
      BINARY SEARCH
      ASSIGNING <LFS_T001>.                       "会社コード
    IF SY-SUBRC = 0.
      <LFS_DATA>-BUTXT = <LFS_T001>-BUTXT.        "会社コードまたは会社の名称
    ENDIF.

    READ TABLE LDT_T024 WITH KEY                  "購買グループ
        EKGRP = <LFS_DATA>-EKGRP                  "購買グループ
      BINARY SEARCH
      ASSIGNING <LFS_T024>.                       "購買グループ
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKNAM = <LFS_T024>-EKNAM.        "購買グループテキスト
    ENDIF.

    READ TABLE LDT_T024E WITH KEY                 "購買組織
        EKORG = <LFS_DATA>-EKORG                  "購買組織
      BINARY SEARCH
      ASSIGNING <LFS_T024E>.                      "購買組織
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKOTX = <LFS_T024E>-EKOTX.       "購買組織テキスト
    ENDIF.

    READ TABLE LDT_T001W WITH KEY                 "プラント/支店
        WERKS = <LFS_DATA>-WERKS                  "プラント
      BINARY SEARCH
      ASSIGNING <LFS_T001W>.                      "プラント/支店
    IF SY-SUBRC = 0.
      <LFS_DATA>-NAME1 = <LFS_T001W>-NAME1.       "名称
    ENDIF.

    READ TABLE LDT_T001L WITH KEY                 "保管場所
        WERKS = <LFS_DATA>-WERKS                  "プラント
        LGORT = <LFS_DATA>-LGORT                  "保管場所
      BINARY SEARCH
      ASSIGNING <LFS_T001L>.                      "保管場所
    IF SY-SUBRC = 0.
      <LFS_DATA>-LGOBE = <LFS_T001L>-LGOBE.       "保管場所テキスト
    ENDIF.

  ENDLOOP.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'EKET' ).
  SELECT FROM EKET FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 16 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT17).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 17 TEXT = LDF_COUNT17 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_731P1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票明細一覧を取得します。
  "伝票番号、伝票タイプ等、組織情報等、数量、明細納入期日の最小および最大を取得します。
  TYPES:
    BEGIN OF LTS_DATA,
      EBELN      TYPE EKPO-EBELN,                 "購買伝票番号
      EBELP      TYPE EKPO-EBELP,                 "購買伝票の明細番号
      BSART      TYPE EKKO-BSART,                 "購買伝票タイプ
      EKKO_LOEKZ TYPE EKKO-LOEKZ,                 "購買伝票の削除フラグ:ヘッダ
      PSTYP      TYPE EKPO-PSTYP,                 "購買伝票の明細カテゴリ
      EKPO_LOEKZ TYPE EKPO-LOEKZ,                 "購買伝票の削除フラグ:明細
      BUKRS      TYPE EKKO-BUKRS,                 "会社コード
      BUTXT      TYPE T001-BUTXT,                 "会社コードまたは会社の名称
      EKGRP      TYPE EKKO-EKGRP,                 "購買グループ
      EKNAM      TYPE T024-EKNAM,                 "購買グループテキスト
      EKORG      TYPE EKKO-EKORG,                 "購買組織
      EKOTX      TYPE T024E-EKOTX,                "購買組織テキスト
      WERKS      TYPE EKPO-WERKS,                 "プラント
      NAME1      TYPE T001W-NAME1,                "名称
      LGORT      TYPE EKPO-LGORT,                 "保管場所
      LGOBE      TYPE T001L-LGOBE,                "保管場所テキスト
      MATNR      TYPE EKPO-MATNR,                 "品目コード
      TXZ01      TYPE EKPO-TXZ01,                 "テキスト (短)
      MENGE      TYPE EKPO-MENGE,                 "購買発注量
      MEINS      TYPE EKPO-MEINS,                 "発注単位
      EINDT_MIN  TYPE EKET-EINDT,                 "明細納入期日:最小
      EINDT_MAX  TYPE EKET-EINDT,                 "明細納入期日:最大
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.

  DATA:
    LDT_DATA TYPE LTT_DATA.

  SELECT
      EKPO~EBELN                                  "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
      EKKO~BSART                                  "購買伝票タイプ
      EKKO~LOEKZ AS EKKO_LOEKZ                    "購買伝票の削除フラグ:ヘッダ
      EKPO~PSTYP                                  "購買伝票の明細カテゴリ
      EKPO~LOEKZ AS EKPO_LOEKZ                    "購買伝票の削除フラグ:明細
      EKKO~BUKRS                                  "会社コード
      T001~BUTXT                                  "会社コードまたは会社の名称
      EKKO~EKGRP                                  "購買グループ
      T024~EKNAM                                  "購買グループテキスト
      EKKO~EKORG                                  "購買組織
      T024E~EKOTX                                 "購買組織テキスト
      EKPO~WERKS                                  "プラント
      T001W~NAME1                                 "名称
      EKPO~LGORT                                  "保管場所
      T001L~LGOBE                                 "保管場所テキスト
      EKPO~MATNR                                  "品目コード
      EKPO~TXZ01                                  "テキスト (短)
      EKPO~MENGE                                  "購買発注量
      EKPO~MEINS                                  "発注単位
      MIN( EKET~EINDT ) AS EINDT_MIN              "明細納入期日:最小
      MAX( EKET~EINDT ) AS EINDT_MAX              "明細納入期日:最大
    INTO TABLE LDT_DATA
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    LEFT OUTER JOIN EKET                          "分納契約納入日程行
       ON EKET~EBELN = EKPO~EBELN                 "購買伝票番号
      AND EKET~EBELP = EKPO~EBELP                 "購買伝票の明細番号
    LEFT OUTER JOIN T001                          "会社コード
       ON T001~BUKRS = EKKO~BUKRS                 "会社コード
    LEFT OUTER JOIN T024                          "購買グループ
       ON T024~EKGRP = EKKO~EKGRP                 "購買グループ
    LEFT OUTER JOIN T024E                         "購買組織
       ON T024E~EKORG = EKKO~EKORG                "購買組織
    LEFT OUTER JOIN T001W                         "プラント/支店
       ON T001W~WERKS = EKPO~WERKS                "プラント
    LEFT OUTER JOIN T001L                         "保管場所
       ON T001L~WERKS = EKPO~WERKS                "プラント
      AND T001L~LGORT = EKPO~LGORT                "保管場所
    GROUP BY
      EKPO~EBELN                                  "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
      EKKO~BSART                                  "購買伝票タイプ
      EKKO~LOEKZ                                  "購買伝票の削除フラグ:ヘッダ
      EKPO~PSTYP                                  "購買伝票の明細カテゴリ
      EKPO~LOEKZ                                  "購買伝票の削除フラグ:明細
      EKKO~BUKRS                                  "会社コード
      T001~BUTXT                                  "会社コードまたは会社の名称
      EKKO~EKGRP                                  "購買グループ
      T024~EKNAM                                  "購買グループテキスト
      EKKO~EKORG                                  "購買組織
      T024E~EKOTX                                 "購買組織テキスト
      EKPO~WERKS                                  "プラント
      T001W~NAME1                                 "名称
      EKPO~LGORT                                  "保管場所
      T001L~LGOBE                                 "保管場所テキスト
      EKPO~MATNR                                  "品目コード
      EKPO~TXZ01                                  "テキスト (短)
      EKPO~MENGE                                  "購買発注量
      EKPO~MEINS                                  "発注単位
    ORDER BY
      EKPO~EBELN                                  "購買伝票番号
      EKPO~EBELP.                                 "購買伝票の明細番号

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'EKET' ).
  SELECT FROM EKET FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 16 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT17).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 17 TEXT = LDF_COUNT17 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740P2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票明細一覧を取得します。
  "伝票番号、伝票タイプ等、組織情報等、数量、明細納入期日の最小および最大を取得します。
  TYPES:
    BEGIN OF LTS_DATA,
      EBELN      TYPE EKPO-EBELN,                 "購買伝票番号
      EBELP      TYPE EKPO-EBELP,                 "購買伝票の明細番号
      BSART      TYPE EKKO-BSART,                 "購買伝票タイプ
      EKKO_LOEKZ TYPE EKKO-LOEKZ,                 "購買伝票の削除フラグ:ヘッダ
      PSTYP      TYPE EKPO-PSTYP,                 "購買伝票の明細カテゴリ
      EKPO_LOEKZ TYPE EKPO-LOEKZ,                 "購買伝票の削除フラグ:明細
      BUKRS      TYPE EKKO-BUKRS,                 "会社コード
      BUTXT      TYPE T001-BUTXT,                 "会社コードまたは会社の名称
      EKGRP      TYPE EKKO-EKGRP,                 "購買グループ
      EKNAM      TYPE T024-EKNAM,                 "購買グループテキスト
      EKORG      TYPE EKKO-EKORG,                 "購買組織
      EKOTX      TYPE T024E-EKOTX,                "購買組織テキスト
      WERKS      TYPE EKPO-WERKS,                 "プラント
      NAME1      TYPE T001W-NAME1,                "名称
      LGORT      TYPE EKPO-LGORT,                 "保管場所
      LGOBE      TYPE T001L-LGOBE,                "保管場所テキスト
      MATNR      TYPE EKPO-MATNR,                 "品目コード
      TXZ01      TYPE EKPO-TXZ01,                 "テキスト (短)
      MENGE      TYPE EKPO-MENGE,                 "購買発注量
      MEINS      TYPE EKPO-MEINS,                 "発注単位
      EINDT_MIN  TYPE EKET-EINDT,                 "明細納入期日:最小
      EINDT_MAX  TYPE EKET-EINDT,                 "明細納入期日:最大
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.

  DATA:
    LDT_DATA TYPE LTT_DATA.

  WITH
  +EKXX AS (                                      "購買伝票
  SELECT
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP,                                 "購買伝票の明細番号
      EKKO~BSART,                                 "購買伝票タイプ
      EKKO~LOEKZ AS EKKO_LOEKZ,                   "購買伝票の削除フラグ:ヘッダ
      EKPO~PSTYP,                                 "購買伝票の明細カテゴリ
      EKPO~LOEKZ AS EKPO_LOEKZ,                   "購買伝票の削除フラグ:明細
      EKKO~BUKRS,                                 "会社コード
      EKKO~EKGRP,                                 "購買グループ
      EKKO~EKORG,                                 "購買組織
      EKPO~WERKS,                                 "プラント
      EKPO~LGORT,                                 "保管場所
      EKPO~MATNR,                                 "品目コード
      EKPO~TXZ01,                                 "テキスト (短)
      EKPO~MENGE,                                 "購買発注量
      EKPO~MEINS,                                 "発注単位
      EKET~EINDT                                  "明細納入期日
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    LEFT OUTER JOIN EKET                          "分納契約納入日程行
       ON EKET~EBELN = EKPO~EBELN                 "購買伝票番号
      AND EKET~EBELP = EKPO~EBELP                 "購買伝票の明細番号
  ),
  +EKPO AS (                                      "購買伝票明細
  SELECT
      +EKXX~EBELN,                                "購買伝票番号
      +EKXX~EBELP,                                "購買伝票の明細番号
      +EKXX~BSART,                                "購買伝票タイプ
      +EKXX~EKKO_LOEKZ,                           "購買伝票の削除フラグ:ヘッダ
      +EKXX~PSTYP,                                "購買伝票の明細カテゴリ
      +EKXX~EKPO_LOEKZ,                           "購買伝票の削除フラグ:明細
      +EKXX~BUKRS,                                "会社コード
      +EKXX~EKGRP,                                "購買グループ
      +EKXX~EKORG,                                "購買組織
      +EKXX~WERKS,                                "プラント
      +EKXX~LGORT,                                "保管場所
      +EKXX~MATNR,                                "品目コード
      +EKXX~TXZ01,                                "テキスト (短)
      +EKXX~MENGE,                                "購買発注量
      +EKXX~MEINS                                 "発注単位
    FROM +EKXX                                    "購買伝票
    GROUP BY
      +EKXX~EBELN,                                "購買伝票番号
      +EKXX~EBELP,                                "購買伝票の明細番号
      +EKXX~BSART,                                "購買伝票タイプ
      +EKXX~EKKO_LOEKZ,                           "購買伝票の削除フラグ:ヘッダ
      +EKXX~PSTYP,                                "購買伝票の明細カテゴリ
      +EKXX~EKPO_LOEKZ,                           "購買伝票の削除フラグ:明細
      +EKXX~BUKRS,                                "会社コード
      +EKXX~EKGRP,                                "購買グループ
      +EKXX~EKORG,                                "購買組織
      +EKXX~WERKS,                                "プラント
      +EKXX~LGORT,                                "保管場所
      +EKXX~MATNR,                                "品目コード
      +EKXX~TXZ01,                                "テキスト (短)
      +EKXX~MENGE,                                "購買発注量
      +EKXX~MEINS                                 "発注単位
  ),
  +EKET AS (                                      "分納契約納入日程行
  SELECT
      +EKXX~EBELN,                                "購買伝票番号
      +EKXX~EBELP,                                "購買伝票の明細番号
      MIN( +EKXX~EINDT ) AS EINDT_MIN,            "明細納入期日:最小
      MAX( +EKXX~EINDT ) AS EINDT_MAX             "明細納入期日:最大
    FROM +EKXX                                    "購買伝票
    GROUP BY
      +EKXX~EBELN,                                "購買伝票番号
      +EKXX~EBELP                                 "購買伝票の明細番号
  )
  SELECT
      +EKPO~EBELN,                                "購買伝票番号
      +EKPO~EBELP,                                "購買伝票の明細番号
      +EKPO~BSART,                                "購買伝票タイプ
      +EKPO~EKKO_LOEKZ,                           "購買伝票の削除フラグ:ヘッダ
      +EKPO~PSTYP,                                "購買伝票の明細カテゴリ
      +EKPO~EKPO_LOEKZ,                           "購買伝票の削除フラグ:明細
      +EKPO~BUKRS,                                "会社コード
      T001~BUTXT,                                 "会社コードまたは会社の名称
      +EKPO~EKGRP,                                "購買グループ
      T024~EKNAM,                                 "購買グループテキスト
      +EKPO~EKORG,                                "購買組織
      T024E~EKOTX,                                "購買組織テキスト
      +EKPO~WERKS,                                "プラント
      T001W~NAME1,                                "名称
      +EKPO~LGORT,                                "保管場所
      T001L~LGOBE,                                "保管場所テキスト
      +EKPO~MATNR,                                "品目コード
      +EKPO~TXZ01,                                "テキスト (短)
      +EKPO~MENGE,                                "購買発注量
      +EKPO~MEINS,                                "発注単位
      +EKET~EINDT_MIN,                            "明細納入期日:最小
      +EKET~EINDT_MAX                             "明細納入期日:最大
    FROM +EKPO                                    "購買伝票明細
    LEFT OUTER JOIN +EKET                         "分納契約納入日程行
       ON +EKET~EBELN = +EKPO~EBELN               "購買伝票番号
      AND +EKET~EBELP = +EKPO~EBELP               "購買伝票の明細番号
    LEFT OUTER JOIN T001                          "会社コード
       ON T001~BUKRS = +EKPO~BUKRS                "会社コード
    LEFT OUTER JOIN T024                          "購買グループ
       ON T024~EKGRP = +EKPO~EKGRP                "購買グループ
    LEFT OUTER JOIN T024E                         "購買組織
       ON T024E~EKORG = +EKPO~EKORG               "購買組織
    LEFT OUTER JOIN T001W                         "プラント/支店
       ON T001W~WERKS = +EKPO~WERKS               "プラント
    LEFT OUTER JOIN T001L                         "保管場所
       ON T001L~WERKS = +EKPO~WERKS               "プラント
      AND T001L~LGORT = +EKPO~LGORT               "保管場所
    ORDER BY
      +EKPO~EBELN,                                "購買伝票番号
      +EKPO~EBELP                                 "購買伝票の明細番号
    INTO TABLE @LDT_DATA.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'EKET' ).
  SELECT FROM EKET FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 16 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT17).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 17 TEXT = LDF_COUNT17 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740P3
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票明細一覧を取得します。
  "伝票番号、伝票タイプ等、組織情報等、数量、明細納入期日の最小および最大を取得します。
  TYPES:
    BEGIN OF LTS_DATA,
      EBELN      TYPE EKPO-EBELN,                 "購買伝票番号
      EBELP      TYPE EKPO-EBELP,                 "購買伝票の明細番号
      BSART      TYPE EKKO-BSART,                 "購買伝票タイプ
      EKKO_LOEKZ TYPE EKKO-LOEKZ,                 "購買伝票の削除フラグ:ヘッダ
      PSTYP      TYPE EKPO-PSTYP,                 "購買伝票の明細カテゴリ
      EKPO_LOEKZ TYPE EKPO-LOEKZ,                 "購買伝票の削除フラグ:明細
      BUKRS      TYPE EKKO-BUKRS,                 "会社コード
      BUTXT      TYPE T001-BUTXT,                 "会社コードまたは会社の名称
      EKGRP      TYPE EKKO-EKGRP,                 "購買グループ
      EKNAM      TYPE T024-EKNAM,                 "購買グループテキスト
      EKORG      TYPE EKKO-EKORG,                 "購買組織
      EKOTX      TYPE T024E-EKOTX,                "購買組織テキスト
      WERKS      TYPE EKPO-WERKS,                 "プラント
      NAME1      TYPE T001W-NAME1,                "名称
      LGORT      TYPE EKPO-LGORT,                 "保管場所
      LGOBE      TYPE T001L-LGOBE,                "保管場所テキスト
      MATNR      TYPE EKPO-MATNR,                 "品目コード
      TXZ01      TYPE EKPO-TXZ01,                 "テキスト (短)
      MENGE      TYPE EKPO-MENGE,                 "購買発注量
      MEINS      TYPE EKPO-MEINS,                 "発注単位
      EINDT_MIN  TYPE EKET-EINDT,                 "明細納入期日:最小
      EINDT_MAX  TYPE EKET-EINDT,                 "明細納入期日:最大
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.

  DATA:
    LDT_DATA TYPE LTT_DATA.

  WITH
  +EKET AS (                                      "分納契約納入日程行
  SELECT
      EKET~EBELN,                                 "購買伝票番号
      EKET~EBELP,                                 "購買伝票の明細番号
      MIN( EKET~EINDT ) AS EINDT_MIN,             "明細納入期日:最小
      MAX( EKET~EINDT ) AS EINDT_MAX              "明細納入期日:最大
    FROM EKET                                     "分納契約納入日程行
    GROUP BY
      EKET~EBELN,                                 "購買伝票番号
      EKET~EBELP                                  "購買伝票の明細番号
     )
  SELECT
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP,                                 "購買伝票の明細番号
      EKKO~BSART,                                 "購買伝票タイプ
      EKKO~LOEKZ AS EKKO_LOEKZ,                   "購買伝票の削除フラグ:ヘッダ
      EKPO~PSTYP,                                 "購買伝票の明細カテゴリ
      EKPO~LOEKZ AS EKPO_LOEKZ,                   "購買伝票の削除フラグ:明細
      EKKO~BUKRS,                                 "会社コード
      T001~BUTXT,                                 "会社コードまたは会社の名称
      EKKO~EKGRP,                                 "購買グループ
      T024~EKNAM,                                 "購買グループテキスト
      EKKO~EKORG,                                 "購買組織
      T024E~EKOTX,                                "購買組織テキスト
      EKPO~WERKS,                                 "プラント
      T001W~NAME1,                                "名称
      EKPO~LGORT,                                 "保管場所
      T001L~LGOBE,                                "保管場所テキスト
      EKPO~MATNR,                                 "品目コード
      EKPO~TXZ01,                                 "テキスト (短)
      EKPO~MENGE,                                 "購買発注量
      EKPO~MEINS,                                 "発注単位
      +EKET~EINDT_MIN,                            "明細納入期日:最小
      +EKET~EINDT_MAX                             "明細納入期日:最大
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    LEFT OUTER JOIN +EKET                         "分納契約納入日程行
       ON +EKET~EBELN = EKPO~EBELN                "購買伝票番号
      AND +EKET~EBELP = EKPO~EBELP                "購買伝票の明細番号
    LEFT OUTER JOIN T001                          "会社コード
       ON T001~BUKRS = EKKO~BUKRS                 "会社コード
    LEFT OUTER JOIN T024                          "購買グループ
       ON T024~EKGRP = EKKO~EKGRP                 "購買グループ
    LEFT OUTER JOIN T024E                         "購買組織
       ON T024E~EKORG = EKKO~EKORG                "購買組織
    LEFT OUTER JOIN T001W                         "プラント/支店
       ON T001W~WERKS = EKPO~WERKS                "プラント
    LEFT OUTER JOIN T001L                         "保管場所
       ON T001L~WERKS = EKPO~WERKS                "プラント
      AND T001L~LGORT = EKPO~LGORT                "保管場所
    ORDER BY
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
    INTO TABLE @LDT_DATA.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'EKET' ).
  SELECT FROM EKET FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 16 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT17).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 17 TEXT = LDF_COUNT17 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

検索キーワード
ABAP
ABAP 7.31
ABAP 7.4
ABAP 7.50
ABAP 7.51
ABAP 7.52
SQL
Open SQL
New Open SQL
Classic Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP ERP 6.0
SAP S/4HANA
SELECT
JOIN
INNER JOIN
OUTER JOIN
LEFT OUTER JOIN
GROUP BY
ORDER BY

ABAP New open SQL:Code Pushdown って何のこと?

Code Pushdown ってなんのことだろう?

2023-08-13:続編があります。こっちのほうがより実践的かもしれない。
ABAP New open SQL:Code Pushdown って何のこと?(2) - コントロールを取り戻せ!
ABAP New open SQL:Code Pushdown って何のこと?(3) - コントロールを取り戻せ!
2023-08-13:比較記事を書きました。(ABAP)CDS View vs HANA(Information)View
ABAP CDS View vs HANA Information View(HANA View):メモリ使用量比較|基幹システムのクラウド移行・構築・導入支援のBeeX

  • 先日、SAP HANAの勉強会に参加したときのこと。
  • 多少時代遅れ感はありますが、「ABAP CDS View vs HANA Infomation View」のスライドがありまして、ざっくり体感的には、HANA Infomation Viewが3倍から30倍くらい高速に動作します。
  • 一時期、営業的なのかどうか不明ですが、SAPJ様が「ABAP CDS Viewのほうが速い」と発信していたらしいですが、実測してみると、HANA Infomation Viewの圧勝で、SAP HANAの仕組みを少し考えると、当然ということに気づきます。
  • ただし、1千万~10億レコードといったボリュームの大きなデータを扱うときの話で、プロジェクトでアドオンプログラム(10万レコード程度)のパフォーマンスが出なくて困っていることとリンクしていないことが、なかなか伝わらないようでした。
  • アドオンプログラムの場合、Netweaverのメモリ容量制限から、扱えるのは500万レコード位でしょうか?桁が違う話なのです。
  • パフォーマンスが正義みたいな考え方はあまり好きでは無いのですが、R/3時代のルールで作成した(ITAB多用)プログラムも含めて乱暴な比較をすると以下のような感じになると思います。
    • 1:ITAB多用(BINARY SEARCH等をガチガチに組んだ場合)
    • 100:ABAP CDS View(パフォーマンス上は、Classic Open SQL、New Open SQLも同じ)
    • 1000:HANA Infomation View

(数値が大きい方が高速動作)

昔々SAP社様が、「東京→大阪を数秒で行ける」といった宣伝をしていました。
「ITAB多用で、2時間30分→9,000秒、,1,000倍高速なHANA Infomation Viewで置き換えに成功したとすると、9秒」
条件付きではありますが、嘘は言っていなかったと思います。
でも、これが90秒でもおそらく万々歳だと思うのです。そして、New Open SQLのみで実現できるとしたら...嬉しいですよね。

一方で営業的には、
「リアルタイム経営の為には、ビックデータの高速分析が必要です。Code Pushdownという設計手法があり、CDS Viewを採用することで実現します。」
CDS→Pushdown→リアルタイム経営」みたいな。

多少逆説的ですが、ABAPコードの中の「LOOP文を、廃止または削減」すると、Code Pushdownが実現できると思います。そして処理速度100倍も夢ではないと思います。っということでプログラムを作ってみました。
外見上の振る舞いは変えずに5種類の実装方法を作りました。
処理としては、トランザクションを格納したテーブルから、会社コードのバリエーション一覧を取得します。

A-1
 従来方式です。
 ACDOCAのデータを取得して
 SORT命令で並び替えて(Non-Pushdown)
 DELETE命令で重複を削除する(Non-Pushdown)

A-2
 従来方式の変形です。
 ACDOCAのデータをORDER BY句で並び替えて取得して(Pushdown)
 DELETE命令で重複を削除する(Non-Pushdown)

B-1
 ACDOCAのデータをDISTINCT句で重複削除して(Pushdown)
 ORDER BY句で並び替えて取得する(Pushdown)

B-2
 ACDOCAのデータをGROUP BY句で重複削除して(Pushdown)
 ORDER BY句で並び替えて取得する(Pushdown)

C-1
 番外編
 ACDOCAのデータを取得して
 LOOP + BINARY SEARCHで、重複削除および並び替えする(Non-Pushdown)

私の環境では以下の通りになりました。
ACDOCA:300万レコード→実行結果:20レコード
A-1:2.9sec
A-2:1.0sec
B-1:0.018sec
B-2:0.018sec
C-1:3.0sec
純粋なITAB(Non-Pushdown)のA-1とC-1と比較して、PushdownしているB-1、B-2は100倍以上の処理速度となりました。
そして、HANA Infomation Viewはこれより更に10倍高速動作する可能性があります。

ABAP CDS Viewは、ABAP層で動作しているので、Open SQL(New, Classic含む)とほぼ同じ速度です。だから、使い慣れたOpen SQLにちょい足しをして、もっとカジュアルにCode Pushdownすると良いのではと思います。

2023-08-14:ラジオボタンで選択できるように修正。バグ修正

*&---------------------------------------------------------------------*
*& Report SQL_Console
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT SQL_Console.

*-----------------------------------------------------------------------
* GLOBAL VARIABLE
*-----------------------------------------------------------------------
DATA:
  GDS_BAPIRET2 TYPE BAPIRET2,                     "リターンパラメータ
  GDF_SUBRC    TYPE SY-SUBRC.                     "リターンコード

*-----------------------------------------------------------------------
* CONDITION VIEW
*-----------------------------------------------------------------------

PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ
PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数
PARAMETERS:
  P_740A1 RADIOBUTTON GROUP RB1,                 "A-1:ACDOCAのデータを取得して、SORT命令で並び替えて、DELETE命令で重複を削除する
  P_740A2 RADIOBUTTON GROUP RB1,                 "A-2:ACDOCAのデータをORDER BY句で並び替えて取得して、"DELETE命令で重複を削除する
  P_740B1 RADIOBUTTON GROUP RB1,                 "B-1:ACDOCAのデータをDISTINCT句で重複削除して、ORDER BY句で並び替えて取得する
  P_740B2 RADIOBUTTON GROUP RB1,                 "B-2:ACDOCAのデータをGROUP BY句で重複削除して、ORDER BY句で並び替えて取得する
  P_740C1 RADIOBUTTON GROUP RB1.                 "C-1:番外編、ACDOCAのデータを取得して、LOOP + BINARY SEARCHで、重複削除および並び替えする

*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  CASE ABAP_TRUE.
    WHEN P_740A1.
      PERFORM START_OF_SELECTION_740A1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740A2.
      PERFORM START_OF_SELECTION_740A2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740B1.
      PERFORM START_OF_SELECTION_740B1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740B2.
      PERFORM START_OF_SELECTION_740B2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_740C1.
      PERFORM START_OF_SELECTION_740C1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN OTHERS.
      LEAVE TO LIST-PROCESSING.
  ENDCASE.

*-----------------------------------------------------------------------
* SUBROUTINE
*-----------------------------------------------------------------------
FORM START_OF_SELECTION_740A1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "ACDOCAに登録済みの会社コードを並び替えて一覧出力する
  SELECT
      ACDOCA~RBUKRS
    FROM ACDOCA
    INTO TABLE @DATA(LDT_DATA).
  SORT LDT_DATA ASCENDING BY
    RBUKRS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING
    RBUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ).
  SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740A2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "ACDOCAに登録済みの会社コードを並び替えて一覧出力する
  SELECT
      ACDOCA~RBUKRS
    FROM ACDOCA
    ORDER BY
      ACDOCA~RBUKRS
    INTO TABLE @DATA(LDT_DATA).
  DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING
    RBUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ).
  SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740B1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "ACDOCAに登録済みの会社コードを並び替えて一覧出力する
  SELECT DISTINCT
      ACDOCA~RBUKRS
    FROM ACDOCA
    ORDER BY
      ACDOCA~RBUKRS
    INTO TABLE @DATA(LDT_DATA).

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ).
  SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740B2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "ACDOCAに登録済みの会社コードを並び替えて一覧出力する
  SELECT
      ACDOCA~RBUKRS
    FROM ACDOCA
    GROUP BY
      ACDOCA~RBUKRS
    ORDER BY
      ACDOCA~RBUKRS
    INTO TABLE @DATA(LDT_DATA).

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ).
  SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_740C1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "ACDOCAに登録済みの会社コードを並び替えて一覧出力する
  SELECT
      ACDOCA~RBUKRS
    FROM ACDOCA
    INTO TABLE @DATA(LDT_DATA_1).
  DATA LDT_DATA LIKE LDT_DATA_1.
  LOOP AT LDT_DATA_1 ASSIGNING FIELD-SYMBOL(<LFS_DATA_1>).
    READ TABLE LDT_DATA
        TRANSPORTING NO FIELDS
        WITH KEY RBUKRS = <LFS_DATA_1>-RBUKRS
        BINARY SEARCH.
    IF SY-SUBRC <> 0.
      INSERT <LFS_DATA_1>
          INTO LDT_DATA
          INDEX SY-TABIX.
      CONTINUE.
    ENDIF.
  ENDLOOP.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'ACDOCA' ).
  SELECT FROM ACDOCA FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

参考までに、Non-SAP HANA(Oracle 10.2)で動作するSAP ERP 6.0で同様の検証をしてみました。
以下ソースコードは、ABAP 7.31で動作しています。そのため、Classic Open SQLで記述しています。
ACDOCAは無いので、BKPFで実装しました。

BKPF:32万レコード→実行結果:150レコード
A-1:0.21sec
A-2:0.15sec
B-1:0.10sec
B-2:0.11sec
C-1:0.22sec

データ量が少なかったのでドラスティックな差は出ませんでしたが、Non-PushdownのA-1、C-1が大体0.2sec、PushdownのB-1、B-2が大体0.1sec、半分ずつのA-2が結果も中間の0.15secとなりました。さすがにOracleも10.2くらい新しいと、Pushdownした方が良好な結果になりました。実際は、ITABを高速に扱うのは高度なスキルが必要と思います。過不足なくBINARY SEARCHを完璧に使えているプログラムはほとんどないと思います。だから実際はもっと差がつくと思います。

2023-08-14:ラジオボタンで選択できるように修正。

*&---------------------------------------------------------------------*
*& Report SQL_Console
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT SQL_Console.

*-----------------------------------------------------------------------
* GLOBAL VARIABLE
*-----------------------------------------------------------------------
DATA:
  GDS_BAPIRET2 TYPE BAPIRET2,                     "リターンパラメータ
  GDF_SUBRC    TYPE SY-SUBRC.                     "リターンコード

*-----------------------------------------------------------------------
* CONDITION VIEW
*-----------------------------------------------------------------------

PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ
PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数
PARAMETERS:
  P_731A1 RADIOBUTTON GROUP RB1,                 "A-1:BKPFのデータを取得して、SORT命令で並び替えて、DELETE命令で重複を削除する
  P_731A2 RADIOBUTTON GROUP RB1,                 "A-2:BKPFのデータをORDER BY句で並び替えて取得して、"DELETE命令で重複を削除する
  P_731B1 RADIOBUTTON GROUP RB1,                 "B-1:BKPFのデータをDISTINCT句で重複削除して、ORDER BY句で並び替えて取得する
  P_731B2 RADIOBUTTON GROUP RB1,                 "B-2:BKPFのデータをGROUP BY句で重複削除して、ORDER BY句で並び替えて取得する
  P_731C1 RADIOBUTTON GROUP RB1.                 "C-1:番外編、BKPFのデータを取得して、LOOP + BINARY SEARCHで、重複削除および並び替えする

*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  CASE ABAP_TRUE.
    WHEN P_731A1.
      PERFORM START_OF_SELECTION_731A1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_731A2.
      PERFORM START_OF_SELECTION_731A2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_731B1.
      PERFORM START_OF_SELECTION_731B1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_731B2.
      PERFORM START_OF_SELECTION_731B2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_731C1.
      PERFORM START_OF_SELECTION_731C1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN OTHERS.
      LEAVE TO LIST-PROCESSING.
  ENDCASE.

*-----------------------------------------------------------------------
* SUBROUTINE
*-----------------------------------------------------------------------
FORM START_OF_SELECTION_731A1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
  "BKPFに登録済みの会社コードを並び替えて一覧出力する

  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE BSEG-BUKRS,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
  DATA:
    LDT_DATA TYPE LTT_DATA.

  SELECT
      BKPF~BUKRS
    INTO TABLE LDT_DATA
    FROM BKPF.
  SORT LDT_DATA ASCENDING BY
    BUKRS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING
    BUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA LDF_DATA_COUNT TYPE INT4.
  DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT.
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ).
  DATA LDF_COUNT3 TYPE INT4.
  SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3.
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_731A2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
  "BKPFに登録済みの会社コードを並び替えて一覧出力する

  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE BSEG-BUKRS,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
  DATA:
    LDT_DATA TYPE LTT_DATA.

  SELECT
      BKPF~BUKRS
    INTO TABLE LDT_DATA
    FROM BKPF
    ORDER BY
      BKPF~BUKRS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA COMPARING
    BUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA LDF_DATA_COUNT TYPE INT4.
  DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT.
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ).
  DATA LDF_COUNT3 TYPE INT4.
  SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3.
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_731B1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
  "BKPFに登録済みの会社コードを並び替えて一覧出力する

  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE BSEG-BUKRS,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
  DATA:
    LDT_DATA TYPE LTT_DATA.

  SELECT DISTINCT
      BKPF~BUKRS
    INTO TABLE LDT_DATA
    FROM BKPF
    ORDER BY
      BKPF~BUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA LDF_DATA_COUNT TYPE INT4.
  DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT.
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ).
  DATA LDF_COUNT3 TYPE INT4.
  SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3.
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_731B2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
  "BKPFに登録済みの会社コードを並び替えて一覧出力する

  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE BSEG-BUKRS,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
  DATA:
    LDT_DATA TYPE LTT_DATA.

  SELECT
      BKPF~BUKRS
    INTO TABLE LDT_DATA
    FROM BKPF
    GROUP BY
      BKPF~BUKRS
    ORDER BY
      BKPF~BUKRS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA LDF_DATA_COUNT TYPE INT4.
  DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT.
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ).
  DATA LDF_COUNT3 TYPE INT4.
  SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3.
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_731C1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始
  "BKPFに登録済みの会社コードを並び替えて一覧出力する

  TYPES:
    BEGIN OF LTS_DATA,
      BUKRS TYPE BSEG-BUKRS,
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.
  DATA:
    LDT_DATA TYPE LTT_DATA.

  DATA LDT_DATA_1 LIKE LDT_DATA.
  FIELD-SYMBOLS <LFS_DATA_1> LIKE LINE OF LDT_DATA_1.
  SELECT
      BKPF~BUKRS
    INTO TABLE LDT_DATA_1
    FROM BKPF.
  LOOP AT LDT_DATA_1 ASSIGNING <LFS_DATA_1>.
    READ TABLE LDT_DATA
        TRANSPORTING NO FIELDS
        WITH KEY BUKRS = <LFS_DATA_1>-BUKRS
        BINARY SEARCH.
    IF SY-SUBRC <> 0.
      INSERT <LFS_DATA_1>
          INTO LDT_DATA
          INDEX SY-TABIX.
      CONTINUE.
    ENDIF.
  ENDLOOP.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA LDF_DATA_COUNT TYPE INT4.
  DESCRIBE TABLE LDT_DATA LINES LDF_DATA_COUNT.
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  DATA:
    LDO_ALV      TYPE REF TO CL_SALV_TABLE,
    LDX_SALV_MSG TYPE REF TO CX_SALV_MSG.
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = LDO_ALV
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO LDX_SALV_MSG.
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  "ヘッダ表示
  DATA LDO_HEADER TYPE REF TO CL_SALV_FORM_LAYOUT_GRID.
  CREATE OBJECT LDO_HEADER TYPE CL_SALV_FORM_LAYOUT_GRID.
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'BKPF' ).
  DATA LDF_COUNT3 TYPE INT4.
  SELECT COUNT(*) FROM BKPF INTO LDF_COUNT3.
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

当初は、DISTINCTとGROUP BYのどちらが速いか?をテーマにしようと思っていたのですが、急遽変更しました。

5年くらい前はGROUP BYの圧勝だったんだけれど、今回なんかねぇ~あまり差がつかなかったんだよね~。

以上

検索キーワード
ABAP
ABAP 7.31
ABAP 7.4
ABAP 7.50
ABAP 7.51
ABAP 7.52
SQL
Open SQL
New Open SQL
Classic Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP ERP 6.0
SAP S/4HANA

最近のヘビロテです。
www.youtube.com

ABAP New open SQL:FOR ALL ENTRIES IN + BINARY SEARCHから逃れたい

ABAP New open SQL:FOR ALL ENTRIES IN + BINARY SEARCHから逃れたい

SAPが、Code Pushdownと言おうが、
SAPが、Code to Dataと言おうが、
データーベース様には迷惑をかけられない!!!
データーベースはそっとしておきたい!!
(本音では)データーベースを信じてはいけない!
だって、BSEGで先輩たちに怒られ続けたから。

こんなところでしょうか?

だから、ITABにせっせとマスタ情報を溜め込む。
FOR ALL ENTRIES INを使って。
いつしかFOR ALL ENTRIES INを使うために。
準備をして、準備をして、確認して、確認して、えいっ!!てね。
業務ロジックに無関係のコードがたくさん生まれる。
データの並び順に細心の注意を払って。
そしてBINARY SEARCHを使うために下準備を念入りに。

時代は流れてHANAでABAPが動く。
ちょっと前でもORA10。

もうやめようよって思います。
SAPがCode Pushdownって言う遥か前から、一般(非ABAP)と同じようにデータベースにおまかせしようよ。
そう思います。
昔々ORA7とかの頃は信じてはいけなかったかもしれないけれど、もう信じようよ。

っというわけで、FOR ALL ENTRIES IN。
数年前にSAPトレーニング(HA400)を受講したときは、New Open SQLで書き換えできないのはFOR ALL ENTRIES INだけ、あとはRANGE TABLEを含めてすべて書き換え可能と教わりました。
先日、逃げ回っていたFOR ALL ENTRIES INのヘルプを見たら、サンプルコードがNew Open SQLで書かれていました。それと同時に、制約事項もたくさん書かれていました。やっぱり、いろいろ気にしなければいけないことが多いのね。

そこで、これまた先日見つけた必殺技。
「WITH句 + SELECT〜FROM @ITAB」
これ行けます。
FOR ALL ENTRIES INはすべて「WITH句 + SELECT〜FROM @ITAB」で書き換え可能です。そして、使うための下ごしらえもほぼ不要。HANA に一時テーブルという仕組みがあったことを改めて思い出しました。そういえば、HANA Infomation Viewの途中を覗き見するときに、知らないうちに使っていたよな。ABAP 7.52から追加されたWITH句もHANAでは一時テーブルが動いていると考えると辻褄が合うと思います。

プログラムの説明
3種類の方法で、外見上の振る舞いが同じになるように、実装しています。
A:PERFORM START_OF_SELECTION_LOOP1 "FOR ALL ENTRIES IN句を使用してテキスト情報を取得
  コード量(ロジック部分のみ):256行
  従来型の実装です。
  トランザクションデータを使ってFOR ALL ENTRIES IN句でマスタデータをフィルタし取得します。
  BINARY SEARCHでマスタ情報を特定して、各種名称を補完します。
  FOR ALL ENTRIES IN句の直前で、ブランクチェック、SORT命令DELETE命令による重複削除します。
  BINARY SEARCHの手前で、SORT命令による並び替えをします。

B:PERFORM START_OF_SELECTION_LOOP2 "WITH句 + SELECT〜FROM @ITABを使用してテキスト情報を取得
  コード量(ロジック部分のみ):224行
  今回のテーマです。
  WITH句の前半で、トランザクションデータの重複削除します。
  後半でINNER JOINすることでマスタデータのフィルタ取得および、並び替えをします。
  BINARY SEARCHでマスタ情報を特定して、各種名称を補完します。
  直前の、ブランクチェック、SORT命令DELETE命令による重複削除は不要です。
  BINARY SEARCHの手前の並び替えはORDER BY句で行います。

C:PERFORM START_OF_SELECTION_JOIN "テーブルJOINでテキスト情報を取得
  コード量(ロジック部分のみ):62行
  本来あるべき姿
  マスタ情報は、SELECT文のJOIN句で表結合します。

パフォーマンスについて
  約4万件取得で、いずれも0.06~0.07secでした。
 JOINによるパフォーマンス悪化を懸念する人がいると思います。
  以前、単一トランザクションテーブルに対して、約30のマスタテーブルをJOIN句結合しました。
  パフォーマンス悪化は無かったです。(1秒以内で処理終了していました)
 データベースの並列実行に対するパフォーマンス悪化を懸念する人がいると思います。
  数年前に測定したところ、感覚値として50並列位すると、処理時間が1.5倍程度になります。
 個人的には、有り余るSAP HANAのパフォーマンスを遊ばせるのは、エンドユーザの利益と相反すると思います。

ソースコード保守性
 Cの「テーブルJOINでテキスト情報を取得」が圧倒的大差で、コード量が少なくなります。
 (256行→62行:なんと1/4以下!!!)
 コード量が少ないと、バグの入り込む余地が大幅に減ります。
 影響範囲についても、そもそもコード量全体が少ないので、問題にはならないと思います。
 SELECT文については、「情報処理技術者ITパスポート試験」でも出題するので、
 苦手な人は、ご自身のバリューを保つため、勉強しましょう。(むちゃぶり!!?ですか?)

2023-08-14:ラジオボタンで選択できるように修正。

*&---------------------------------------------------------------------*
*& Report SQL_CONSOLE
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT SQL_CONSOLE.

*-----------------------------------------------------------------------
* GLOBAL VARIABLE
*-----------------------------------------------------------------------
DATA:
  GDS_BAPIRET2 TYPE BAPIRET2,                     "リターンパラメータ
  GDF_SUBRC    TYPE SY-SUBRC.                     "リターンコード

*-----------------------------------------------------------------------
* CONDITION VIEW
*-----------------------------------------------------------------------

PARAMETERS P_ISDISP AS CHECKBOX TYPE UFVISIBLE DEFAULT ABAP_FALSE."表示フラグ
PARAMETERS P_TBMAXS TYPE TBMAXSEL DEFAULT 1000000."選択するエントリの最大数
PARAMETERS:
  P_LOOP1 RADIOBUTTON GROUP RB1,                  "FOR ALL ENTRIES IN句を使用してテキスト情報を取得
  P_LOOP2 RADIOBUTTON GROUP RB1,                  "WITH句 + SELECT〜FROM @ITABを使用してテキスト情報を取得
  P_JOIN  RADIOBUTTON GROUP RB1.                  "テーブルJOINでテキスト情報を取得

*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  CASE ABAP_TRUE.
    WHEN P_LOOP1.
      PERFORM START_OF_SELECTION_LOOP1
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_LOOP2.
      PERFORM START_OF_SELECTION_LOOP2
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN P_JOIN.
      PERFORM START_OF_SELECTION_JOIN
        USING
          P_ISDISP                                "表示フラグ
          P_TBMAXS                                "選択するエントリの最大数
        CHANGING
          GDS_BAPIRET2                            "リターンパラメータ
          GDF_SUBRC.                              "リターンコード
      IF GDF_SUBRC <> 0.                          "リターンコード
        LEAVE TO LIST-PROCESSING.
      ENDIF.
    WHEN OTHERS.
      LEAVE TO LIST-PROCESSING.
  ENDCASE.

*-----------------------------------------------------------------------
* SUBROUTINE
*-----------------------------------------------------------------------
FORM START_OF_SELECTION_LOOP1
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票に各種マスタ情報を付加する。
  TYPES:
    BEGIN OF LTS_DATA,                            "一覧データ
      EBELN TYPE EKPO-EBELN,                      "購買伝票番号
      EBELP TYPE EKPO-EBELP,                      "購買伝票の明細番号
      EKORG TYPE EKKO-EKORG,                      "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
      EKGRP TYPE EKKO-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
      BUKRS TYPE EKKO-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
      MATNR TYPE EKPO-MATNR,                      "品目コード
      TXZ01 TYPE EKPO-TXZ01,                      "テキスト (短)
      WERKS TYPE EKPO-WERKS,                      "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
      LGORT TYPE EKPO-LGORT,                      "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
      MENGE TYPE EKPO-MENGE,                      "購買発注量
      MEINS TYPE EKPO-MEINS,                      "発注単位
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA,     "一覧データ

    BEGIN OF LTS_T024E,                           "購買組織
      EKORG TYPE T024E-EKORG,                     "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
    END OF LTS_T024E,
    LTT_T024E TYPE STANDARD TABLE OF LTS_T024E,   "購買組織

    BEGIN OF LTS_T024,                            "購買グループ
      EKGRP TYPE T024-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
    END OF LTS_T024,
    LTT_T024 TYPE STANDARD TABLE OF LTS_T024,     "購買グループ

    BEGIN OF LTS_T001,                            "会社コード
      BUKRS TYPE T001-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
    END OF LTS_T001,
    LTT_T001 TYPE STANDARD TABLE OF LTS_T001,     "会社コード

    BEGIN OF LTS_T001W,                           "プラント/支店
      WERKS TYPE T001W-WERKS,                     "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
    END OF LTS_T001W,
    LTT_T001W TYPE STANDARD TABLE OF LTS_T001W,   "プラント/支店

    BEGIN OF LTS_T001L,                           "保管場所
      WERKS TYPE T001L-WERKS,                     "プラント
      LGORT TYPE T001L-LGORT,                     "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
    END OF LTS_T001L,
    LTT_T001L TYPE STANDARD TABLE OF LTS_T001L.   "保管場所

  DATA:
    LDT_DATA  TYPE LTT_DATA,                      "一覧データ
    LDT_DATA1 TYPE LTT_DATA,                      "一覧データ:作業用

    LDT_T024E TYPE LTT_T024E,                     "購買組織
    LDS_T024E LIKE LINE OF LDT_T024E,             "購買組織
    LDT_T024  TYPE LTT_T024,                      "購買グループ
    LDS_T024  LIKE LINE OF LDT_T024,              "購買グループ
    LDT_T001  TYPE LTT_T001,                      "会社コード
    LDS_T001  LIKE LINE OF LDT_T001,              "会社コード
    LDT_T001W TYPE LTT_T001W,                     "プラント/支店
    LDS_T001W LIKE LINE OF LDT_T001W,             "プラント/支店
    LDT_T001L TYPE LTT_T001L,                     "保管場所
    LDS_T001L LIKE LINE OF LDT_T001L.             "保管場所

  SELECT
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP,                                 "購買伝票の明細番号
      EKKO~EKORG,                                 "購買組織
      EKKO~EKGRP,                                 "購買グループ
      EKKO~BUKRS,                                 "会社コード
      EKPO~MATNR,                                 "品目コード
      EKPO~TXZ01,                                 "テキスト (短)
      EKPO~WERKS,                                 "プラント
      EKPO~LGORT,                                 "保管場所
      EKPO~MENGE,                                 "購買発注量
      EKPO~MEINS                                  "発注単位
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    ORDER BY
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
    INTO CORRESPONDING FIELDS OF TABLE @LDT_DATA. "一覧データ
  IF SY-SUBRC <> 0.
    POF_SUBRC = 4.
    RETURN.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1 = LDT_DATA.                           "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      EKORG.                                      "購買組織
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      EKORG.                                      "購買組織
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T024E~EKORG,                              "購買組織
        T024E~EKOTX                               "購買組織テキスト
      FROM T024E                                  "購買組織
      FOR ALL ENTRIES IN @LDT_DATA1               "一覧データ:作業用
      WHERE T024E~EKORG = @LDT_DATA1-EKORG        "購買組織
      INTO TABLE @LDT_T024E.                      "購買組織
    IF SY-SUBRC = 0.
      SORT LDT_T024E ASCENDING BY                 "購買組織
          EKORG.                                  "購買組織
      DELETE ADJACENT DUPLICATES FROM LDT_T024E COMPARING"購買組織
          EKORG.                                  "購買組織
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1 = LDT_DATA.                           "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      EKGRP.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      EKGRP.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T024~EKGRP,                               "購買グループ
        T024~EKNAM                                "購買グループテキスト
      FROM T024                                   "購買グループ
      FOR ALL ENTRIES IN @LDT_DATA1               "一覧データ:作業用
      WHERE T024~EKGRP = @LDT_DATA1-EKGRP         "購買グループ
      INTO TABLE @LDT_T024.                       "購買グループ
    IF SY-SUBRC = 0.
      SORT LDT_T024 ASCENDING BY                  "購買グループ
          EKGRP.                                  "購買グループ
      DELETE ADJACENT DUPLICATES FROM LDT_T024 COMPARING"購買グループ
          EKGRP.                                  "購買グループ
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1 = LDT_DATA.                           "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      BUKRS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      BUKRS.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001~BUKRS,                               "会社コード
        T001~BUTXT                                "会社コードまたは会社の名称
      FROM T001
      FOR ALL ENTRIES IN @LDT_DATA1               "一覧データ:作業用
      WHERE T001~BUKRS = @LDT_DATA1-BUKRS         "会社コード
      INTO TABLE @LDT_T001.                       "会社コード
    IF SY-SUBRC = 0.
      SORT LDT_T001 ASCENDING BY                  "会社コード
          BUKRS.                                  "会社コード
      DELETE ADJACENT DUPLICATES FROM LDT_T001 COMPARING"会社コード
          BUKRS.                                  "会社コード
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1 = LDT_DATA.                           "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      WERKS.
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      WERKS.
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001W~WERKS,                              "プラント
        T001W~NAME1                               "名称
      FROM T001W                                  "プラント/支店
      FOR ALL ENTRIES IN @LDT_DATA1               "一覧データ:作業用
      WHERE T001W~WERKS = @LDT_DATA1-WERKS        "プラント
      INTO TABLE @LDT_T001W.                      "プラント/支店
    IF SY-SUBRC = 0.
      SORT LDT_T001W ASCENDING BY                 "プラント/支店
          WERKS.                                  "プラント
      DELETE ADJACENT DUPLICATES FROM LDT_T001W COMPARING"プラント/支店
          WERKS.                                  "プラント
    ENDIF.
  ENDIF.

  CLEAR LDT_DATA1.                                "一覧データ:作業用
  LDT_DATA1 = LDT_DATA.                           "一覧データ:作業用
  SORT LDT_DATA1 ASCENDING BY                     "一覧データ:作業用
      WERKS                                       "プラント
      LGORT.                                      "保管場所
  DELETE ADJACENT DUPLICATES FROM LDT_DATA1 COMPARING"一覧データ:作業用
      WERKS                                       "プラント
      LGORT.                                      "保管場所
  IF LDT_DATA1 IS NOT INITIAL.                    "一覧データ:作業用
    SELECT
        T001L~WERKS,                              "プラント
        T001L~LGORT,                              "保管場所
        T001L~LGOBE                               "保管場所テキスト
      FROM T001L                                  "保管場所
      FOR ALL ENTRIES IN @LDT_DATA1               "一覧データ:作業用
      WHERE T001L~WERKS = @LDT_DATA1-WERKS        "プラント
        AND T001L~LGORT = @LDT_DATA1-LGORT        "保管場所
      INTO TABLE @LDT_T001L.                      "保管場所
    IF SY-SUBRC = 0.
      SORT LDT_T001L ASCENDING BY                 "保管場所
          WERKS                                   "プラント
          LGORT.                                  "保管場所
      DELETE ADJACENT DUPLICATES FROM LDT_T001L COMPARING
          WERKS                                   "プラント
          LGORT.                                  "保管場所
    ENDIF.
  ENDIF.

  LOOP AT LDT_DATA ASSIGNING FIELD-SYMBOL(<LFS_DATA>)."一覧データ

    CLEAR LDS_T024E.                              "購買組織
    READ TABLE LDT_T024E WITH KEY                 "購買組織
        EKORG = <LFS_DATA>-EKORG                  "購買組織
      BINARY SEARCH
      INTO LDS_T024E.                             "購買組織
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKOTX = LDS_T024E-EKOTX.         "購買組織テキスト
    ENDIF.

    CLEAR LDS_T024.                               "購買グループ
    READ TABLE LDT_T024 WITH KEY                  "購買グループ
        EKGRP = <LFS_DATA>-EKGRP                  "購買グループ
      BINARY SEARCH
      INTO LDS_T024.                              "購買グループ
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKNAM = LDS_T024-EKNAM.          "購買グループテキスト
    ENDIF.

    CLEAR LDS_T001.                               "会社コード
    READ TABLE LDT_T001 WITH KEY                  "会社コード
        BUKRS = <LFS_DATA>-BUKRS                  "会社コード
      BINARY SEARCH
      INTO LDS_T001.                              "会社コード
    IF SY-SUBRC = 0.
      <LFS_DATA>-BUTXT = LDS_T001-BUTXT.          "会社コードまたは会社の名称
    ENDIF.

    CLEAR LDS_T001W.                              "プラント/支店
    READ TABLE LDT_T001W WITH KEY                 "プラント/支店
        WERKS = <LFS_DATA>-WERKS                  "プラント
      BINARY SEARCH
      INTO LDS_T001W.                             "プラント/支店
    IF SY-SUBRC = 0.
      <LFS_DATA>-NAME1 = LDS_T001W-NAME1.         "名称
    ENDIF.

    CLEAR LDS_T001L.                              "保管場所
    READ TABLE LDT_T001L WITH KEY                 "保管場所
        WERKS = <LFS_DATA>-WERKS                  "プラント
        LGORT = <LFS_DATA>-LGORT                  "保管場所
      BINARY SEARCH
      INTO LDS_T001L.                             "保管場所
    IF SY-SUBRC = 0.
      <LFS_DATA>-LGOBE = LDS_T001L-LGOBE.         "保管場所テキスト
    ENDIF.

  ENDLOOP.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_LOOP2
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票に各種マスタ情報を付加する。
  TYPES:
    BEGIN OF LTS_DATA,                            "一覧データ
      EBELN TYPE EKPO-EBELN,                      "購買伝票番号
      EBELP TYPE EKPO-EBELP,                      "購買伝票の明細番号
      EKORG TYPE EKKO-EKORG,                      "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
      EKGRP TYPE EKKO-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
      BUKRS TYPE EKKO-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
      MATNR TYPE EKPO-MATNR,                      "品目コード
      TXZ01 TYPE EKPO-TXZ01,                      "テキスト (短)
      WERKS TYPE EKPO-WERKS,                      "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
      LGORT TYPE EKPO-LGORT,                      "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
      MENGE TYPE EKPO-MENGE,                      "購買発注量
      MEINS TYPE EKPO-MEINS,                      "発注単位
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA,     "一覧データ

    BEGIN OF LTS_T024E,                           "購買組織
      EKORG TYPE T024E-EKORG,                     "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
    END OF LTS_T024E,
    LTT_T024E TYPE STANDARD TABLE OF LTS_T024E,   "購買組織

    BEGIN OF LTS_T024,                            "購買グループ
      EKGRP TYPE T024-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
    END OF LTS_T024,
    LTT_T024 TYPE STANDARD TABLE OF LTS_T024,     "購買グループ

    BEGIN OF LTS_T001,                            "会社コード
      BUKRS TYPE T001-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
    END OF LTS_T001,
    LTT_T001 TYPE STANDARD TABLE OF LTS_T001,     "会社コード

    BEGIN OF LTS_T001W,                           "プラント/支店
      WERKS TYPE T001W-WERKS,                     "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
    END OF LTS_T001W,
    LTT_T001W TYPE STANDARD TABLE OF LTS_T001W,   "プラント/支店

    BEGIN OF LTS_T001L,                           "保管場所
      WERKS TYPE T001L-WERKS,                     "プラント
      LGORT TYPE T001L-LGORT,                     "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
    END OF LTS_T001L,
    LTT_T001L TYPE STANDARD TABLE OF LTS_T001L.   "保管場所

  DATA:
    LDT_DATA  TYPE LTT_DATA,                      "一覧データ

    LDT_T024E TYPE LTT_T024E,                     "購買組織
    LDS_T024E LIKE LINE OF LDT_T024E,             "購買組織
    LDT_T024  TYPE LTT_T024,                      "購買グループ
    LDS_T024  LIKE LINE OF LDT_T024,              "購買グループ
    LDT_T001  TYPE LTT_T001,                      "会社コード
    LDS_T001  LIKE LINE OF LDT_T001,              "会社コード
    LDT_T001W TYPE LTT_T001W,                     "プラント/支店
    LDS_T001W LIKE LINE OF LDT_T001W,             "プラント/支店
    LDT_T001L TYPE LTT_T001L,                     "保管場所
    LDS_T001L LIKE LINE OF LDT_T001L.             "保管場所

  SELECT
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP,                                 "購買伝票の明細番号
      EKKO~EKORG,                                 "購買組織
      EKKO~EKGRP,                                 "購買グループ
      EKKO~BUKRS,                                 "会社コード
      EKPO~MATNR,                                 "品目コード
      EKPO~TXZ01,                                 "テキスト (短)
      EKPO~WERKS,                                 "プラント
      EKPO~LGORT,                                 "保管場所
      EKPO~MENGE,                                 "購買発注量
      EKPO~MEINS                                  "発注単位
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    ORDER BY
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
    INTO CORRESPONDING FIELDS OF TABLE @LDT_DATA. "一覧データ
  IF SY-SUBRC <> 0.
    POF_SUBRC = 4.
    RETURN.
  ENDIF.

  WITH
  +LDT_DATA AS ( SELECT                           "一覧データ
      LDT_DATA~EKORG                              "購買組織
    FROM @LDT_DATA AS LDT_DATA                    "一覧データ
    GROUP BY
      LDT_DATA~EKORG )                            "購買組織
  SELECT
      T024E~EKORG,                                "購買組織
      T024E~EKOTX                                 "購買組織テキスト
    FROM T024E                                    "購買組織
    INNER JOIN +LDT_DATA                          "一覧データ
       ON +LDT_DATA~EKORG = T024E~EKORG           "購買組織
    ORDER BY
      T024E~EKORG                                 "購買組織
    INTO TABLE @LDT_T024E.                        "購買組織

  WITH
  +LDT_DATA AS ( SELECT                           "一覧データ
      LDT_DATA~EKGRP                              "購買グループ
    FROM @LDT_DATA AS LDT_DATA                    "一覧データ
    GROUP BY
      LDT_DATA~EKGRP )                            "購買グループ
  SELECT
      T024~EKGRP,                                 "購買グループ
      T024~EKNAM                                  "購買グループテキスト
    FROM T024                                     "購買グループ
    INNER JOIN +LDT_DATA                          "一覧データ
       ON +LDT_DATA~EKGRP = T024~EKGRP            "購買グループ
    ORDER BY
      T024~EKGRP                                  "購買グループ
    INTO TABLE @LDT_T024.                         "購買グループ

  WITH
  +LDT_DATA AS ( SELECT                           "一覧データ
      LDT_DATA~BUKRS                              "会社コード
    FROM @LDT_DATA AS LDT_DATA                    "一覧データ
    GROUP BY
      LDT_DATA~BUKRS )                            "会社コード
  SELECT
      T001~BUKRS,                                 "会社コード
      T001~BUTXT                                  "会社コードまたは会社の名称
    FROM T001                                     "会社コード
    INNER JOIN +LDT_DATA                          "一覧データ
       ON +LDT_DATA~BUKRS = T001~BUKRS            "会社コード
    ORDER BY
      T001~BUKRS                                  "会社コード
    INTO TABLE @LDT_T001.                         "会社コード

  WITH
  +LDT_DATA AS ( SELECT                           "一覧データ
      LDT_DATA~WERKS                              "プラント
    FROM @LDT_DATA AS LDT_DATA                    "一覧データ
    GROUP BY
      LDT_DATA~WERKS )                            "プラント
  SELECT
      T001W~WERKS,                                "プラント
      T001W~NAME1                                 "名称
    FROM T001W                                    "プラント/支店
    INNER JOIN +LDT_DATA                          "一覧データ
       ON +LDT_DATA~WERKS = T001W~WERKS           "プラント
    ORDER BY
      T001W~WERKS                                 "プラント
    INTO TABLE @LDT_T001W.                        "プラント/支店

  WITH
  +LDT_DATA AS ( SELECT                           "一覧データ
      LDT_DATA~WERKS,                             "プラント
      LDT_DATA~LGORT                              "保管場所
    FROM @LDT_DATA AS LDT_DATA                    "一覧データ
    GROUP BY
      LDT_DATA~WERKS,                             "プラント
      LDT_DATA~LGORT )                            "保管場所
  SELECT
      T001L~WERKS,                                "プラント
      T001L~LGORT,                                "保管場所
      T001L~LGOBE                                 "保管場所テキスト
    FROM T001L                                    "保管場所
    INNER JOIN +LDT_DATA                          "一覧データ
       ON +LDT_DATA~WERKS = T001L~WERKS           "プラント
      AND +LDT_DATA~LGORT = T001L~LGORT           "保管場所
    ORDER BY
      T001L~WERKS,                                "プラント
      T001L~LGORT                                 "保管場所
    INTO TABLE @LDT_T001L.                        "保管場所

  LOOP AT LDT_DATA ASSIGNING FIELD-SYMBOL(<LFS_DATA>)."一覧データ

    CLEAR LDS_T024E.                              "購買組織
    READ TABLE LDT_T024E WITH KEY                 "購買組織
        EKORG = <LFS_DATA>-EKORG                  "購買組織
      BINARY SEARCH
      INTO LDS_T024E.                             "購買組織
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKOTX = LDS_T024E-EKOTX.         "購買組織テキスト
    ENDIF.

    CLEAR LDS_T024.                               "購買グループ
    READ TABLE LDT_T024 WITH KEY                  "購買グループ
        EKGRP = <LFS_DATA>-EKGRP                  "購買グループ
      BINARY SEARCH
      INTO LDS_T024.                              "購買グループ
    IF SY-SUBRC = 0.
      <LFS_DATA>-EKNAM = LDS_T024-EKNAM.          "購買グループテキスト
    ENDIF.

    CLEAR LDS_T001.                               "会社コード
    READ TABLE LDT_T001 WITH KEY                  "会社コード
        BUKRS = <LFS_DATA>-BUKRS                  "会社コード
      BINARY SEARCH
      INTO LDS_T001.                              "会社コード
    IF SY-SUBRC = 0.
      <LFS_DATA>-BUTXT = LDS_T001-BUTXT.          "会社コードまたは会社の名称
    ENDIF.

    CLEAR LDS_T001W.                              "プラント/支店
    READ TABLE LDT_T001W WITH KEY                 "プラント/支店
        WERKS = <LFS_DATA>-WERKS                  "プラント
      BINARY SEARCH
      INTO LDS_T001W.                             "プラント/支店
    IF SY-SUBRC = 0.
      <LFS_DATA>-NAME1 = LDS_T001W-NAME1.         "名称
    ENDIF.

    CLEAR LDS_T001L.                              "保管場所
    READ TABLE LDT_T001L WITH KEY                 "保管場所
        WERKS = <LFS_DATA>-WERKS                  "プラント
        LGORT = <LFS_DATA>-LGORT                  "保管場所
      BINARY SEARCH
      INTO LDS_T001L.                             "保管場所
    IF SY-SUBRC = 0.
      <LFS_DATA>-LGOBE = LDS_T001L-LGOBE.         "保管場所テキスト
    ENDIF.

  ENDLOOP.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

FORM START_OF_SELECTION_JOIN
    USING
      PIF_ISDISP   TYPE CHECKBOX
      PIF_TBMAXSEL TYPE TBMAXSEL
    CHANGING
      POS_BAPIRET2 TYPE BAPIRET2
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
  CLEAR:
      POS_BAPIRET2,                               "リターンパラメータ
      POF_SUBRC.                                  "リターンコード
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  "購買伝票に各種マスタ情報を付加する。
  TYPES:
    BEGIN OF LTS_DATA,                            "一覧データ
      EBELN TYPE EKPO-EBELN,                      "購買伝票番号
      EBELP TYPE EKPO-EBELP,                      "購買伝票の明細番号
      EKORG TYPE EKKO-EKORG,                      "購買組織
      EKOTX TYPE T024E-EKOTX,                     "購買組織テキスト
      EKGRP TYPE EKKO-EKGRP,                      "購買グループ
      EKNAM TYPE T024-EKNAM,                      "購買グループテキスト
      BUKRS TYPE EKKO-BUKRS,                      "会社コード
      BUTXT TYPE T001-BUTXT,                      "会社コードまたは会社の名称
      MATNR TYPE EKPO-MATNR,                      "品目コード
      TXZ01 TYPE EKPO-TXZ01,                      "テキスト (短)
      WERKS TYPE EKPO-WERKS,                      "プラント
      NAME1 TYPE T001W-NAME1,                     "名称
      LGORT TYPE EKPO-LGORT,                      "保管場所
      LGOBE TYPE T001L-LGOBE,                     "保管場所テキスト
      MENGE TYPE EKPO-MENGE,                      "購買発注量
      MEINS TYPE EKPO-MEINS,                      "発注単位
    END OF LTS_DATA,
    LTT_DATA TYPE STANDARD TABLE OF LTS_DATA.     "一覧データ
  DATA:
    LDT_DATA TYPE LTT_DATA.                       "一覧データ

  SELECT
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP,                                 "購買伝票の明細番号
      EKKO~EKORG,                                 "購買組織
      T024E~EKOTX,                                "購買組織テキスト
      EKKO~EKGRP,                                 "購買グループ
      T024~EKNAM,                                 "購買グループテキスト
      EKKO~BUKRS,                                 "会社コード
      T001~BUTXT,                                 "会社コードまたは会社の名称
      EKPO~MATNR,                                 "品目コード
      EKPO~TXZ01,                                 "テキスト (短)
      EKPO~WERKS,                                 "プラント
      T001W~NAME1,                                "名称
      EKPO~LGORT,                                 "保管場所
      T001L~LGOBE,                                "保管場所テキスト
      EKPO~MENGE,                                 "購買発注量
      EKPO~MEINS                                  "発注単位
    FROM EKPO                                     "購買伝票明細
    INNER JOIN EKKO                               "購買伝票ヘッダ
       ON EKKO~EBELN = EKPO~EBELN                 "購買伝票番号
    LEFT OUTER JOIN T024E                         "購買組織
       ON T024E~EKORG = EKKO~EKORG                "購買組織
    LEFT OUTER JOIN T024                          "購買グループ
       ON T024~EKGRP = EKKO~EKGRP                 "購買グループ
    LEFT OUTER JOIN T001                          "会社コード
       ON T001~BUKRS = EKKO~BUKRS                 "会社コード
    LEFT OUTER JOIN T001W                         "プラント/支店
       ON T001W~WERKS = EKPO~WERKS                "プラント
    LEFT OUTER JOIN T001L                         "保管場所
       ON T001L~WERKS = EKPO~WERKS                "プラント
      AND T001L~LGORT = EKPO~LGORT                "保管場所
    ORDER BY
      EKPO~EBELN,                                 "購買伝票番号
      EKPO~EBELP                                  "購買伝票の明細番号
    INTO TABLE @LDT_DATA.                         "一覧データ
  IF SY-SUBRC <> 0.
    POF_SUBRC = 4.
    RETURN.
  ENDIF.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
  DATA(LDF_DATA_COUNT) = LINES( LDT_DATA ).
  IF PIF_ISDISP = ABAP_FALSE.
    CLEAR LDT_DATA.
  ENDIF.
*-----------------------------------------------------------------------
  TRY.
      CL_SALV_TABLE=>FACTORY(
        IMPORTING
          R_SALV_TABLE = DATA(LDO_ALV)
        CHANGING
          T_TABLE      = LDT_DATA ).
    CATCH CX_SALV_MSG INTO DATA(LDX_SALV_MSG).
      POF_SUBRC = 8.
      RETURN.
  ENDTRY.

  DATA(LDO_HEADER) = NEW CL_SALV_FORM_LAYOUT_GRID( ).
  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 TEXT = 'Performance data' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 1 TEXT = 'Input records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 2 TEXT = 'EKPO' ).
  SELECT FROM EKPO FIELDS COUNT(*) INTO @DATA(LDF_COUNT3).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 3 TEXT = LDF_COUNT3 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 4 TEXT = 'EKKO' ).
  SELECT FROM EKKO FIELDS COUNT(*) INTO @DATA(LDF_COUNT5).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 5 TEXT = LDF_COUNT5 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 6 TEXT = 'T001' ).
  SELECT FROM T001 FIELDS COUNT(*) INTO @DATA(LDF_COUNT7).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 7 TEXT = LDF_COUNT7 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 8 TEXT = 'T024' ).
  SELECT FROM T024 FIELDS COUNT(*) INTO @DATA(LDF_COUNT9).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 9 TEXT = LDF_COUNT9 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 10 TEXT = 'T024E' ).
  SELECT FROM T024E FIELDS COUNT(*) INTO @DATA(LDF_COUNT11).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 11 TEXT = LDF_COUNT11 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 12 TEXT = 'T001W' ).
  SELECT FROM T001W FIELDS COUNT(*) INTO @DATA(LDF_COUNT13).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 13 TEXT = LDF_COUNT13 ).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 14 TEXT = 'T001L' ).
  SELECT FROM T001L FIELDS COUNT(*) INTO @DATA(LDF_COUNT15).
  LDO_HEADER->CREATE_TEXT( ROW = 2 COLUMN = 15 TEXT = LDF_COUNT15 ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 1 TEXT = 'Output records' ).
  LDO_HEADER->CREATE_TEXT( ROW = 3 COLUMN = 2 TEXT = LDF_DATA_COUNT ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 1 TEXT = 'Responce Time [sec]' ).
  LDO_HEADER->CREATE_TEXT( ROW = 4 COLUMN = 2 TEXT = CL_ABAP_TSTMP=>SUBTRACT( TSTMP1 = LDF_TIMESTAMP_END TSTMP2 = LDF_TIMESTAMP_START ) ).

  LDO_ALV->SET_TOP_OF_LIST( LDO_HEADER ).
  LDO_ALV->SET_TOP_OF_LIST_PRINT( LDO_HEADER ).

  LDO_ALV->GET_FUNCTIONS( )->SET_ALL( ).
  LDO_ALV->GET_COLUMNS( )->SET_OPTIMIZE( ).
  LDO_ALV->GET_DISPLAY_SETTINGS( )->SET_STRIPED_PATTERN( ABAP_TRUE ).
  LDO_ALV->GET_SELECTIONS( )->SET_SELECTION_MODE( VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

最近はこんなのを聴いています。
www.youtube.com

検索キーワード
ABAP
ABAP 7.52
SQL
Open SQL
New Open SQL
Classic Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP S/4HANA
WITH
SELECT〜FROM @ITAB
FOR ALL ENTRIES IN

以上

ヘッドホン:MDR-CD900ST:アラウンドイヤー化

連日イヤーパッドに悩んでいました。

DIYヘッドホンとして他の追従を許さないMDR-CD900STイヤーパッド問題です。

私の結論は、MDR-M1ST純正イヤーパッド + シリコーンゴム角紐(SR151) 6×6mm * 100mm で満足しました。
・そこそこのCP
・純正感??!もあり
・入手性も安定している
・装着感の良いアラウンドイヤー
・振動板-鼓膜が短距離となる

https://www.soundhouse.co.jp/products/detail/item/269612/
f:id:dai_h_73:20200321162217j:plain
https://item.rakuten.co.jp/egaos/d12-0002-01_a4/
f:id:dai_h_73:20200321162421j:plain
シリコーンゴム角紐(SR151)をMDR-M1ST純正イヤーパッドにセット(指で押し込むだけ)したところ
f:id:dai_h_73:20200321162709j:plain
なお、シリコーンゴム角紐は、イヤーパッド上部〜後方にかけて押し込むようにセットします。

あまり耳が良く無いので、正確に表現できてないかも知れませんが、装着感が良いにも関わらず、音が近くてストレートで、低音の量感も十分あると思います。MDR-M1ST純正イヤーパッドは振動板をおおうネットが極薄なのでストレートな音になっているように感じます。また、振動板が近いので低音の量感も十分出ていると思います。気持ち良いシンバルサウンド(刺さるような高音とも言う)も健在です。

このヘッドホンは買ってきてそのままだと極薄のイヤーパッドによりギリギリオンイヤーな感じになるんですよね〜。これが賛否両論なんです。賛成派は、イヤーパッドが極薄のためドライバーと耳の距離が近くなるので音がよく分かるということ。反対派はイヤーパッドが極薄のためクッションが浅く耳たぶ付近に隙間を作ってしまい低音の量感が損なわれてしまう。オンイヤーなので耳が潰れてしまい耳が痛くなり長時間の使用に耐えない。反対派のニーズに対応するために、サードパーティ製のイヤーパッドや、他機種の純正流用の話題がつきませんでした。(なぜか過去形)

最近10年くらい前からイヤーパッド面に対して角度を付けてドライバーを固定する方法が主流になっていると思います。
SONY/MDR-1R〜MDR-1A〜
SONY/ MDR-Z1000
SONY/ MDR-M1ST
Audio Tecnica/Art Monitor シリーズ
その他大多数〜
最近気づいたのですが、MDR-CD900ST純正イヤーパッド(ペラペラ)を角度の付いたMDR-Z1000に付けてみると、アラウンドイヤーになるんですねぇ〜驚いたことに!そのためMDR-CD900STのバッフルを加工してドライバーを角度を付けて固定すればアラウンドイヤーになるのではないかとの仮説を立てました。というのは、イヤーパッドとバッフル板の間にほんの少しで良いので空間があると、耳たぶがフィットする様に収まってくれるのです。
モダンなヘッドホン同様にドライバー角度のついたバッフル板をどう作るか?当初は3Dプリンターで作る事を思いつき、3Dデータの作り方を習得するために、渋谷Fab Cafeの講習に参加しました。若くて優秀な講師のおかげで難なく3Dデータを作ることが出来ました。しかしながら十分な精度を確保しようとすると、光学式3Dプリンタ出力を選択する必要があり、バッフル板左右で下手したら万単位のお金が出ていく状況でした。予算的に無理、趣味の範疇を超えている。
いろいろいじくっていて、ひらめきました。イヤーパッドの上部後方、バッフル板とイヤーパッドのフカフカの間に詰め物をしてかさ上げすると、外耳の入るスペースを確保できるのではないか?同時にドライバーも相対的に角度がつくのではないか?更にはオンイヤーの時に外耳の厚み分がアラウンドイヤーになったことで、ドライバーば耳により近くなるのではないか?当初プラ板か何かを加工してこれを詰める事を考えました。しかしながら夜中のためプラ板買いに行けない。試しにティッシュペーパーを丸めたものを詰めてみました。ビンゴでした。
これもしかしたら流行るのではないかと思います。(自画自賛)
何が良いって、材料はティッシュ2枚、そして加工は工具不要で丁寧にやっても20分。そして可逆性があるのでいつでも元に戻せる。
僕は純正ペラペライヤーパッド反対派だったので、サードパーティ製のイヤーパッドをいろいろ試したのですが、純正イヤーパッドティッシュ2枚がとても良く感じます。
しかしながら、いざティッシュ運用してみると、気分の問題なのですが、なんとなく頼りない。そこでインターネットをふらふらしていてたどり着いた素材が、「シリコーンゴム角紐(SR151)」6mmと7mmを購入してみて試したところ、6mmで十分アラウンドイヤーになることを確認出来ました。

MDR-CD900ST純正
MDR-7506純正
ATH-PRO5MK2
と迷走しましたがこれにて一件落着しました。