はじめに
以下の記事で、CDS Viewの日付項目と実行日の差を計算する方法を紹介しました。このような計算はほかのViewでも使う可能性があるので、再利用する方法について考えます。
一つ目の方法は、以下の記事で紹介したCDS Aspectsです。
この記事では、CDS Scaler Functionを使って同じことを実現してみます。
CDS Scaler Function
CDS Scaler Functionは、CDS Viewの中で使うファンクションを独自に定義するものです。SAP BTP ABAP environment 2208およびSAP S/4HANA Cloud 2208から利用できるようになりました。
Version 3.28 | What's New
ファンクションは以下のようにして呼び出すことができます。
function_name(param1 => <設定値>, param2 => <設定値>) as Field1,
CDS Scaler Functionについて、以下の動画で紹介されていました。
Data Modeling with the latest features of ABAP Core Data Services | Youtube
CDS Scalar Functionsで日付項目と実行日の差を計算する関数を作る
Aspectを使用する前のViewの定義は以下のようになっています。
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@EndUserText.label: '###GENERATED Core Data Service Entity'
define root view entity ZR_TODO
as select from ztodo as Todo
{
key id as Id,
title as Title,
detail as Detail,
due_date as DueDate,
//計算項目
tstmp_current_utctimestamp() as TimeStampToday,
tstmp_to_dats($projection.TimeStampToday, 'JAPAN', $session.client, 'NULL') as DateToday,
dats_days_between($projection.DateToday, $projection.DueDate) as DateDifference,
case
when $projection.DateDifference < 0 then 1 //negative: overdue
when $projection.DateDifference < 3 then 2 //critical
else 3 end as Criticality,
//
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.localInstanceLastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}
以下のステップでCDS Scalar Functionを作成し、それを元のCDS Viewに組み込みます。
- Scaler Functionの定義
- AMDPクラスの定義
- Scaler Function Implementation Referenceの定義
- AMDPクラスの実装
- CDS ViewでScalar Functionを利用
BTP ABAP Environment(トライアル)で検証を行っています。
1. Scaler Functionの定義
Core Data Services > Scaler Function Definition を選択します。
名前は最大26桁で、2番目と3番目の位置にアンダースコアがあってはいけないという制約があります。
以下のようにScaler Functionを定義しました。
define scalar function ZDATE_DIFF_FROM_TODAY
with parameters
timezone_in: zde_timezone_hana,
target_date: abap.dats
returns abap.int2
zde_timezone_hana
というデータエレメントにはHANAで定義されているタイムゾーンを指定するため、CHAR 64桁でCase-sensitiveなドメインを定義して使用しています。
2. AMDPクラスの定義
CDS Scaler FunctionのロジックはAMDPで実装します。Interface: IF_AMDP_MARKER_HDB
を実装したクラスを定義します。
3. Scaler Function Implementation Referenceの定義
Scaler Functionを右クリックし、"New Scaler Function Implementation Reference"を選択します。
CDS Viewから呼び出す場合、Engineに"SQL Engine"を選択します。分析クエリから呼び出す場合は"Analytical Engine"を選択します。選択したエンジンに応じて、名前の末尾に"_SQL"または、"_ANA"をつける必要があります。
AMDP Referenceに2.で定義したクラスと、メソッド(未実装)を指定します。ワーニングが出ますが、有効化できます。(メソッド実装後に再有効化が必要)
4. AMDPクラスの実装
Implementation Referenceで指定したexecute
というメソッドを定義します(メソッド名はImplementation Referenceと一致していればなんでもよい)。
Implementation Referenceを先に定義しておかないと、zdate_diff_from_today
というScaler Functionが見つからないというエラーになります。
CLASS zcl_date_diff_from_today_amdp DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb .
CLASS-METHODS execute
FOR SCALAR FUNCTION zdate_diff_from_today.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
メソッドの実装は以下のようになります。
CLASS zcl_date_diff_from_today_amdp IMPLEMENTATION.
METHOD execute BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT.
declare utc_timestamp timestamp;
declare local_timestamp timestamp;
-- today
SELECT current_utctimestamp INTO utc_timestamp FROM dummy;
SELECT utctolocal(:utc_timestamp, :timezone_in) AS local_timestamp INTO local_timestamp FROM dummy;
-- date difference
SELECT days_between(to_date(:local_timestamp), to_date(:target_date)) AS days_between INTO result FROM dummy;
ENDMETHOD.
ENDCLASS.
このメソッドでは以下の計算を行っています。
4.1. 現在の日付を取得する
タイムゾーンを考慮した日付を取得するため、はじめに現在のタイムスタンプを取得し、それを日付型に変換します。
①現在のタイムスタンプを取得する
SELECT current_utctimestamp INTO utc_timestamp FROM dummy;
CURRENT_UTCTIMESTAMPというファンクションで、現在のUTCのタイムスタンプを取得します。
出力例:2024-10-05 20:55:33.965000000
②タイムスタンプを指定したタイムゾーンに変換する
SELECT utctolocal(:utc_timestamp, :timezone_in) AS local_timestamp INTO local_timestamp FROM dummy;
UTCTOLOCALというファンクションで、UTCのタイムスタンプを第二引数で指定したタイムゾーンでのタイムスタンプに変換します。タイムゾーンには、Scaler Functionのインプットである"timezone_in"を指定しています。
出力例:2024-10-06 05:55:33.965000000
指定可能なタイムゾーンはシステムビュー:TIMEZONES
で確認できます。ABAP側で利用するタイムゾーンの値とは異なることに注意が必要です(ABAPの場合、日本は大文字の'JAPAN')。
4.2. 指定された日付との差を計算する
SELECT days_between(to_date(:local_timestamp), to_date(:target_date)) AS days_between INTO result FROM dummy;
DAYS_BETWEEN(date1, date2)というファンクションで、date2からdate1を引いた日数を計算します。TO_DATE()というファンクションは、指定された日付のストリングをDAYDATE型(YYYY-MM-DD)に変換します。
最後に計算結果を格納しているresult
という項目は、Scaler Functionの返り値です。
以下はDatabase Explorerで動作確認した結果です。AMDPはCDS Viewに組み込むまで正しく動くかがわからないので、事前に確認するためにはDatabase Explorerが便利でした。S/4HANAに固有なテーブルはここでは使えませんが、ファンクションなどの動きを確認するのには役立ちます。
5. CDS ViewでScalar Functionを利用
CDS Viewで利用可能にするために、AMDPメソッドを実装したあとでScaler Function Implementation Referenceを再有効化する必要があります。
CDS Viewにもともとあった計算項目をコメントアウトし、Scaler Functionを追加します。
Scaler Functionが"zde_timezone_hana"という型でタイムゾーンを受け取るため、リテラルをその型に変換しています。
cast('Japan' as zde_timezone_hana) as TimeZoneHana,
以下でScaler Functionを呼び出しています。
ZDATE_DIFF_FROM_TODAY( timezone_in => $projection.TimeZoneHana,
target_date => $projection.DueDate ) as DateDifference,
プレビューで見ると、"DateDifference"が正しく計算されています。
Scaler Functionと比較して
CDS Scaler Functionsの場合、最終結果に必要ない項目も計算のために持たなければなりませんが、CDS Scaler Functionsは結果のみ返すので、今回の目的にはより合っています。
ただし、ファンクションの実装をAMDP(SQL Script)で書く必要があるので、CDS Scaler Functionsに比べ実装は難しかったです。