ABAP New open SQL:ACDOCAの日次BS勘定の残高取得

久しぶりの技術系の投稿です。
実はプロジェクトが変わりました。そして、念願(!??)のABAP CDS viewの実装の担当になりました。なのになぜ?ABAP New open SQLなのか?いろいろ実装してみたところ、トライ&エラーを繰り返すのはNew open SQLのほうがやりやすかったからです。
今回紹介するSELECT文は、実プロジェクトでは、ABAP CDS viewに移植しました。パフォーマンスについては未知数ですが、期待した動作をしています。流用するときはご一報ください。知的財産云々もありますが、パフォーマンスデータを共有したいのです。

紹介するプログラムは、以下項目を一覧取得します。
使用したSELECT文の機能要素は以下の通りです。
・WITH句による段階的ロジック
・集合関数:SUM()およびGROUP BYによる集計
・不等号条件によるテーブル自己結合
・HAVING句によるレコードフィルタ
・ORDER BY句による結果セットの並び替え
こんなところでしょうか...

なお、当プログラムは、答え合わせのために、前半はBS勘定の日次の合計金額を単純に出力していて、後半でBS勘定残高を取得しています。そして、パフォーマンスデータも取得できるようにしています。

検索項目
・台帳(必須項目) : 0L :リーディング元帳固定
・会社コード
・会計年度
・勘定コード(BS勘定)

一覧項目
・台帳
・会社コード
・会計年度
・転記日付
・勘定コード(BS勘定)
・会社通貨
・会社通貨の残高(BS残高)

参考1:
ACDOCAのBS残高を取得するには?
ACDOCAのBS残高は、会計年度が切り替わるタイミングで、転記日付初期値の期首残高レコードを作成します。そのため、転記日付2020-07-31時点のBS残高を取得しようとすると、会計年度の期首残高レコードと会計年度期首から転記日付2020-07-31の全ての仕訳明細の合計値を計算します。
従来のITABおよびABAPロジックによるループを使用した実装では、素のACDOCAのレコードを取得して、ループ処理の中で1件ずつ加算していくと思います。おそらくですがオンラインプログラムではパフォーマンスの問題で使い物にならないかもしれません。また、上手に実装しないとソースコードメンテナンスに耐えがたいプログラムになる可能性があります。

参考2:
ABAP CDS Viewの移植に関して。(私的感想)
もしかしたら、ここが最も価値ある情報かもしれません。無いかな。(笑)
実感としては、SAP標準のABAP CDS viewを使わないで開発するのは、非効率的と思いました。一方でSAP標準のABAP CDS viewを考慮した基本設計が出来る人材は稀有です。私が当機能をABAP CDS viewに移植するのに、ABAP CDS viewは都合5個作成しました。作成手順は愚直に1文字ずつSELECT文のコーディング作業となります。従来のITABおよびABAPロジックによるループを使用した実装よりはましですが、正直骨が折れました。
では、自身の中で何がベストかというと...HANA infomation viewをABAP CDS viewでラッピングする方法かなぁ~。パフォーマンスに関してはぶっちぎりで良いと思います。クライアントおよび権限実装についてはABAP CDS viewのラッピング部分で実装すれば良いと思います。Fiori like applicationや、BWを介したAnalysisOfficeへの展開も可能です。機能的には問題ないと思います。そして、HANA infomation viewのドラッグ&ドロップによる実装が群を抜いて効率が良いと思います。PoweruserによるEUCを意識しているので当然と言えば当然ですね。

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

REPORT Y_SQL_CONSOLE.

*-----------------------------------------------------------------------
* GLOBAL VARIABLE
*-----------------------------------------------------------------------
DATA GDF_SUBRC TYPE SY-SUBRC.

*-----------------------------------------------------------------------
* CONDITION VIEW
*-----------------------------------------------------------------------
DATA GDF_RBUKRS TYPE ACDOCA-RBUKRS.
TYPES GTR_RBUKRS LIKE RANGE OF GDF_RBUKRS.
SELECT-OPTIONS S_RBUKRS FOR GDF_RBUKRS.           "会社コード

DATA GDF_RACCT TYPE ACDOCA-RACCT.
TYPES GTR_RACCT LIKE RANGE OF GDF_RACCT.
SELECT-OPTIONS S_RACCT FOR GDF_RACCT.             "勘定コード

*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  PERFORM START_OF_SELECTION
    USING
      S_RBUKRS[]
      S_RACCT[]
    CHANGING
      GDF_SUBRC.

*-----------------------------------------------------------------------
* SUBROUTINE
*-----------------------------------------------------------------------
FORM START_OF_SELECTION
    USING
      PIR_RBUKRS TYPE GTR_RBUKRS
      PIR_RACCT TYPE GTR_RACCT
    CHANGING
      POF_SUBRC TYPE SY-SUBRC.
*-----------------------------------------------------------------------
* Please write the SQL statement here ☆
* Set the internal table to be stored to LDT_DATA ☆
* Inline definition of LDT_DATA is fun ☆
  SELECT
    FROM ACDOCA
    INNER JOIN SKA1
       ON SKA1~KTOPL = ACDOCA~KTOPL
      AND SKA1~SAKNR = ACDOCA~RACCT
      AND SKA1~XBILK = @ABAP_TRUE
    LEFT OUTER JOIN SKAT
       ON SKAT~SPRAS = @SY-LANGU
      AND SKAT~KTOPL = SKA1~KTOPL
      AND SKAT~SAKNR = SKA1~SAKNR
    FIELDS COUNT( * )
    WHERE ACDOCA~RLDNR = '0L'
      AND ACDOCA~RBUKRS IN @PIR_RBUKRS
      AND ACDOCA~RACCT IN @PIR_RACCT
    INTO @DATA(LDF_INPUT_RECORDS).

  SELECT
    FROM ACDOCA
    INNER JOIN SKA1
       ON SKA1~KTOPL = ACDOCA~KTOPL
      AND SKA1~SAKNR = ACDOCA~RACCT
      AND SKA1~XBILK = @ABAP_TRUE
    LEFT OUTER JOIN SKAT
       ON SKAT~SPRAS = @SY-LANGU
      AND SKAT~KTOPL = SKA1~KTOPL
      AND SKAT~SAKNR = SKA1~SAKNR
    FIELDS
      ACDOCA~RLDNR,                               "総勘定元帳の元帳
      ACDOCA~RBUKRS,                              "会社コード
      ACDOCA~GJAHR,                               "会計年度
      ACDOCA~BUDAT,                               "伝票の転記日付
      ACDOCA~RACCT,                               "勘定コード
      SKA1~XBILK,                                 "フラグ: 貸借対照表勘定
      SKAT~TXT20,
      ACDOCA~RHCUR,                               "会社コード通貨
      SUM( ACDOCA~HSL ) AS HSL                    "会社コード通貨での金額
    WHERE ACDOCA~RLDNR = '0L'
      AND ACDOCA~RBUKRS IN @PIR_RBUKRS
      AND ACDOCA~RACCT IN @PIR_RACCT
    GROUP BY
      ACDOCA~RLDNR,                               "総勘定元帳の元帳
      ACDOCA~RBUKRS,                              "会社コード
      ACDOCA~GJAHR,                               "会計年度
      ACDOCA~BUDAT,                               "伝票の転記日付
      ACDOCA~RACCT,                               "勘定コード
      SKA1~XBILK,                                 "フラグ: 貸借対照表勘定
      SKAT~TXT20,
      ACDOCA~RHCUR                               "会社コード通貨
    ORDER BY
      ACDOCA~RBUKRS,                              "会社コード
      ACDOCA~RACCT,                               "勘定コード
      ACDOCA~GJAHR,                               "会計年度
      ACDOCA~BUDAT                                "伝票の転記日付
    APPENDING TABLE @DATA(LDT_DATA) UP TO 10000 ROWS.

  APPEND INITIAL LINE TO LDT_DATA.
  APPEND INITIAL LINE TO LDT_DATA.
  APPEND INITIAL LINE TO LDT_DATA.

  DATA LDF_TIMESTAMP_START TYPE TIMESTAMPL.       "タイムスタンプデータ取得開始
  GET TIME STAMP FIELD LDF_TIMESTAMP_START.       "タイムスタンプデータ取得開始

  WITH
  +ACDOCA AS (
  SELECT
    FROM ACDOCA
    INNER JOIN SKA1
       ON SKA1~KTOPL = ACDOCA~KTOPL
      AND SKA1~SAKNR = ACDOCA~RACCT
      AND SKA1~XBILK = @ABAP_TRUE
    LEFT OUTER JOIN SKAT
       ON SKAT~SPRAS = @SY-LANGU
      AND SKAT~KTOPL = SKA1~KTOPL
      AND SKAT~SAKNR = SKA1~SAKNR
    FIELDS
      ACDOCA~RLDNR,                               "総勘定元帳の元帳
      ACDOCA~RBUKRS,                              "会社コード
      ACDOCA~GJAHR,                               "会計年度
      ACDOCA~BUDAT,                               "伝票の転記日付
      ACDOCA~RACCT,                               "勘定コード
      SKA1~XBILK,                                 "フラグ: 貸借対照表勘定
      SKAT~TXT20,
      ACDOCA~RHCUR,                               "会社コード通貨
      SUM( ACDOCA~HSL ) AS HSL                    "会社コード通貨での金額
    WHERE ACDOCA~RLDNR = '0L'
      AND ACDOCA~RBUKRS IN @PIR_RBUKRS
      AND ACDOCA~RACCT IN @PIR_RACCT
    GROUP BY
      ACDOCA~RLDNR,                               "総勘定元帳の元帳
      ACDOCA~RBUKRS,                              "会社コード
      ACDOCA~GJAHR,                               "会計年度
      ACDOCA~BUDAT,                               "伝票の転記日付
      ACDOCA~RACCT,                               "勘定コード
      SKA1~XBILK,                                 "フラグ: 貸借対照表勘定
      SKAT~TXT20,
      ACDOCA~RHCUR )                              "会社コード通貨
  SELECT
    FROM +ACDOCA AS ACDOCA0
    INNER JOIN +ACDOCA AS ACDOCA1
       ON ACDOCA1~RLDNR = ACDOCA0~RLDNR           "総勘定元帳の元帳
      AND ACDOCA1~RBUKRS = ACDOCA0~RBUKRS         "会社コード
      AND ACDOCA1~GJAHR = ACDOCA0~GJAHR           "会計年度
      AND ACDOCA1~BUDAT <= ACDOCA0~BUDAT          "伝票の転記日付
      AND ACDOCA1~RACCT = ACDOCA0~RACCT           "勘定コード
      AND ACDOCA1~RHCUR = ACDOCA0~RHCUR           "会社コード通貨
    FIELDS
      ACDOCA0~RLDNR,                               "総勘定元帳の元帳
      ACDOCA0~RBUKRS,                              "会社コード
      ACDOCA0~GJAHR,                               "会計年度
      ACDOCA0~BUDAT,                               "伝票の転記日付
      ACDOCA0~RACCT,                               "勘定コード
      ACDOCA0~XBILK,                                 "フラグ: 貸借対照表勘定
      ACDOCA0~TXT20,
      ACDOCA0~RHCUR,                               "会社コード通貨
      SUM( ACDOCA1~HSL ) AS HSL_SUM                "会社コード通貨での金額
    GROUP BY
      ACDOCA0~RLDNR,                               "総勘定元帳の元帳
      ACDOCA0~RBUKRS,                              "会社コード
      ACDOCA0~GJAHR,                               "会計年度
      ACDOCA0~BUDAT,                               "伝票の転記日付
      ACDOCA0~RACCT,                               "勘定コード
      ACDOCA0~XBILK,                                 "フラグ: 貸借対照表勘定
      ACDOCA0~TXT20,
      ACDOCA0~RHCUR                                "会社コード通貨
    HAVING ACDOCA0~BUDAT IS NOT INITIAL            "伝票の転記日付
    ORDER BY
      ACDOCA0~RBUKRS,                              "会社コード
      ACDOCA0~RACCT,                               "勘定コード
      ACDOCA0~GJAHR,                               "会計年度
      ACDOCA0~BUDAT                                "伝票の転記日付
    APPENDING TABLE @LDT_DATA UP TO 10000 ROWS.

  DATA LDF_TIMESTAMP_END TYPE TIMESTAMPL.         "タイムスタンプデータ取得終了
  GET TIME STAMP FIELD LDF_TIMESTAMP_END.         "タイムスタンプデータ取得終了
*-----------------------------------------------------------------------
  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( ).

  DATA(LDO_H_LABEL) = LDO_HEADER->CREATE_LABEL( ROW = 1 COLUMN = 1 ).
  LDO_H_LABEL->SET_TEXT( 'Performance data' ).

  DATA(LDO_H_FLOW) = LDO_HEADER->CREATE_FLOW( ROW = 2  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'Input records' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 2  COLUMN = 2 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_INPUT_RECORDS ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 3  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'Output records' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 3  COLUMN = 2 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = LINES( LDT_DATA ) ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 4  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'Timestamp of start' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 4  COLUMN = 2 ).
  DATA LDF_UTC_START TYPE CHAR30.
  WRITE LDF_TIMESTAMP_START TIME ZONE 'UTC' TO LDF_UTC_START.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_UTC_START ).

  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 5  COLUMN = 1 ).
  LDO_H_FLOW->CREATE_TEXT( TEXT = 'Timestamp of end' ).
  LDO_H_FLOW = LDO_HEADER->CREATE_FLOW( ROW = 5  COLUMN = 2 ).
  DATA LDF_UTC_END TYPE CHAR30.
  WRITE LDF_TIMESTAMP_END TIME ZONE 'UTC' TO LDF_UTC_END.
  LDO_H_FLOW->CREATE_TEXT( TEXT = LDF_UTC_END ).

  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_SELECTIONS( )->SET_SELECTION_MODE( EXPORTING VALUE = IF_SALV_C_SELECTION_MODE=>CELL ).
  LDO_ALV->DISPLAY( ).

  POF_SUBRC = 0.
ENDFORM.

キーワード
検索キーワード
ABAP
ABAP 7.52
New Open SQL
ABAP SQL
SAP HANA
Code to Data
Code Pushdown
SAP S/4HANA
WITH句
集合関数
SUM()
GROUP BY句
JOIN
INNER JOIN
OUTER JOIN
LEFT OUTER JOIN
不等号結合
自己結合
HAVING句
ORDER BY句
CDS view
ABAP CDS view
HANA infomation view



さて本題です。(笑)
今更ですが、感激です。
Vocal : Stevie Wonder
映画 : 蒲田行進曲に出てくる、高見知佳お気に入り!!レジェンド : スティービー・ワンダーです!!
Guiter : Nile Rodgers
Diana Ross/i'm coming out, Diana Ross/Upside down, Madona/Like a Virgin, ...ですよ!!この人一体何枚レコードを売ったのでしょうか?なにより、ファッショナブルで胡散臭いのが好きです。ニューヨークジャズ仕込みのギターテクニックも地味に凄いです。
Drum : Omar Hakim
ウェザー・リポート, マドンナ, スティング, デヴィッド・ボウイ...エレキにも明るくて、ゲロテクです!なにより、プレイ中の表情が好きです。
Bass : Nathan East
Fourplayのベースが一番好きですが、今回は地味に屋台骨を支えています。歌ってないけれど...
このステージメンバーのグラミー受賞数合計は延べ50いくのではと思います。

ファレル ウィリアムス&ナイル ロジャース&スティービー ワンダー&ダフト パンク GET LUCKY グラミー賞 リハーサル



Nile Rodgersのこの動画最高です。Funny!!

Nile Rodgers on I'm Coming Out
ネタ元はおそらくこれですね。

Diana Ross - I'm Coming Out



Guiter : Nile Rodgers
Drum : Omar Hakim

Incredible drumsolo Omar Hakim with Nile Rodgers, Chic, Paradiso 2005 Amsterdam



Bass : Nathan East
Guiter : Chuck Loebのカッティングギターも最高なのですがこれの感想は次の機会に。病死されてしまったのが悲しい。

FourPlay Java Jazz festival 2011
もう一つ

Harvey Mason: 3RD DEGREE (FOURPLAY: Harvey Mason - Chuck Loeb - Bob James - Nathan East)



参考 : Vocal : Diana Ross
イヤー凄いです。マイケルと踊っています。My babyですよ。

"Upside Down" - Michael Jackson at Diana Ross Concert (1980)
JKと踊っています。リスペクトされているんでしょう。

Jamiroquai sings Upside Down with Diana Ross 1997



大人が本気を出すと凄いなぁ~って思います。