ABAP SQL でのコードプッシュダウンの使用

ABAP SQL での特別な組込関数の使用

Objectives

After completing this lesson, you will be able to:
  • データベースの日付、時刻、タイムスタンプを処理します。
  • 組み込み変換関数を使用します。

日付、時刻、タイムスタンプを処理するための関数

日付情報をデータベースフィールドに保存する場合は、以下の 2 つのタイプから選択することができます。

  • DATS には、ABAP で処理される日付が格納されます。つまり、日付は書式 'YYYYMMDD' で長さ 8 の文字として保存されます。
  • DATN は、データベースの日付型に情報を格納します。ABAP SQL を使用してデータベースから情報を読み込むと、自動的に 8 桁の書式に戻されます。

データ型 TIMS と TIMN に同じ違いがあります。

データベース項目にタイムスタンプ情報を保存する場合は、以下の 3 つのタイプから選択することができます。

  • TIMESTAMP は、情報を小数点なしの数値で保存します。数値の桁は、年、月、日、時間、分、秒を表します。
  • TIMESTAMPL は TIMESTAMP と同じですが、では 100 ナノ秒の精度に対応する小数点以下 7 桁までが格納されます。
  • UTCLONG の精度は TIMESTAMPL と同じです。

日付、時刻、タイムスタンプの SQL 関数

ABAP SQL では、日付、時刻、およびタイムスタンプ情報用にさまざまな組み込み関数が提供されます。項目の内容が有効かどうか、計算の機能、または入力引数から特定の情報を抽出する機能をチェックする機能があります。これらの機能の一部を以下に示します。完全な一覧については、ABAP 文書を参照してください。

一部の関数はデータ型固有です。

その他の機能は汎用です。さまざまなタイプの入力を処理できます。たとえば、関数 IS_VALID では、日付、時点、またはタイムスタンプの有効性をチェックすることができます。日付書式 (DATS および DATN) と両方の時間書式 (TIMS および TIMN) が受け入れられます。ただし、タイムスタンプでは、タイプ UTCLONG のみがサポートされています。

場合によっては、タイプ固有機能と一般機能のいずれかを選択することができます。たとえば、データ型 DATS の項目には、DATS_IS_VALID( ) または IS_VALID( ) を使用することができます。より新しい一般機能を優先する必要があります。

注記

ジェネリック関数では、現時点では TIMESTAMP 型と TIMESTAMPL 型のタイムスタンプはサポートされていません。これらのデータ型には、TSTMP_ または TSTMPL_ で始まるデータ型固有の機能を使用する必要があります。

以下は、日付型情報を含む一般関数の使用例です。他のほとんどの SQL 式と同様に、WHERE 句の関数を使用することもできます。ここでは、10 日を超える出張に選択を制限します。

注記

関数 IS_VALID( ) は実論理関数ではありません。true の場合は整数値 1、false の場合は 0 を返します。

試してみる: 日付処理

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    12345678910111213141516171819202122232425
    SELECT FROM /dmo/travel FIELDS begin_date, end_date, is_valid( begin_date ) AS valid, add_days( begin_date, 7 ) AS add_7_days, add_months( begin_date, 3 ) AS add_3_months, days_between( begin_date, end_date ) AS duration, weekday( begin_date ) AS weekday, extract_month( begin_date ) AS month, dayname( begin_date ) AS day_name WHERE customer_id = '000001' AND days_between( begin_date, end_date ) > 10 INTO TABLE @DATA(result). out->write( EXPORTING data = result name = 'RESULT' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。
  5. 日付処理機能の 1 つ (平など) にカーソルを置き、F1 を選択して文書を開きます。
  6. 文書で他の日付処理関数を探し、その機能について理解してみてください。

変換関数

一部の ABAP SQL 変換関数

すべてのデータ型変換を CAST 式で処理できるわけではありません。一部の変換では、ABAP SQL によって特定の変換関数が提供されます (下図参照)。

たとえば、データベース固有の日付表現である DATN から ABAP 固有の文字型日付書式への DATS の変換を実行する SQL 関数 DATS_FROM_DATN があります。SQL 関数 DATS_TO_DATN( ) は、逆方向の変換を実行します。

関数 TSTMP_TO_DATS( ) および TSTMP_TO_TIMS( ) は、タイムスタンプを日付項目と時刻項目にそれぞれ変換します。これらの機能は、技術書式 DEC( 15, 0) のタイムスタンプに対してのみ使用できることに注意してください。その他のタイムスタンプ書式は、これらの関数の入力として機能する前に変換する必要があります。関数 DATS_TIMS_TO_TSTMP は、日付と時刻の情報を 1 つのタイムスタンプに結合します。

変換機能の特別なグループを使用すると、異なる数量単位と通貨間の換算を行うことができます。関数 UNIT_CONVERSION( ) は、ソース単位からターゲット単位に数量を変換します。たとえば、キロメートル単位の距離から同じ距離までの距離をマイル単位で変換します。関数 CURRENCY_CONVERSION( ) では、特定のレポート日付において、ある通貨の金額が別の通貨の同じ金額に変換されます。

注記

CURRENCY_CONVERSION( ) が適切に機能するには、システムのデータベースで時間依存の換算レートが利用可能である必要があります。この方法の詳細については、SAP システム文書を参照してください。

例: タイムスタンプ変換の SQL 関数

この例では、テーブル /DMO/TRAVEL (項目 LASTCHANGEDAT) から UTC タイムスタンプを読み込み、タイムゾーン 'EST' の日付および時刻に変換します。

タイムスタンプは、データ型 TIMESTAMPL、つまり小数点以下 7 桁でデータベーステーブルに保存されます。つまり、SQL 関数の入力パラメータ TSTMP との互換性を確保するために、小数点なしの短いタイムスタンプに変換する必要があります。リテラル 'EST' も、入力パラメータ TZONE と互換性があるように変換する必要があります。

注記

協定世界時 (UTC) と東部標準時 (Eastern Standard Time) の間には 4 時間のタイムシフトがあります。

例: 単位変換の SQL 関数

この例では、フライト接続の距離情報はマイル (MI) に変換され、データベースではキロメートル (KM) で保存されます。

テーブル項目 DISTANCE はデータ型 QUAN ではなく INT4 で定義されるため、入力パラメータ QUANTITY のデータ型と一致するように変換する必要があります。

リテラル 'MI' も 'UNIT' ではなく CHAR(2) 型であるため、変換する必要があります。

注記

この例では、UNIT_CONVERSION( ) の 3 つの必須パラメータのみを提供します。オプションパラメータとその意味の一覧については、ABAP 文書を参照してください。

この例では、出張の合計価格が目標通貨ユーロに換算されます。関数 CURRENCY_CONVERSION には、金額 (項目 TOTAL_PRICE)、元通貨 (項目 CURRENCY_CODE)、target_currency (リテラル 'EUR')、および換算レート決定日 (ABAP 変数 TODAY) が提供されます。SELECT 命令の前に、メソッド呼出で変数 TODAY にシステム日付が入力されます。

注記

この例では、CURRENCY_CONVERSION( ) の 4 つの必須パラメータのみを提供します。オプションパラメータとその意味の一覧については、ABAP 文書を参照してください。

試してみる: 変換機能

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
    SELECT FROM /dmo/travel FIELDS lastchangedat, CAST( lastchangedat AS DEC( 15,0 ) ) AS latstchangedat_short, tstmp_to_dats( tstmp = CAST( lastchangedat AS DEC( 15,0 ) ), tzone = CAST( 'EST' AS CHAR( 6 ) ) ) AS date_est, tstmp_to_tims( tstmp = CAST( lastchangedat AS DEC( 15,0 ) ), tzone = CAST( 'EST' AS CHAR( 6 ) ) ) AS time_est WHERE customer_id = '000001' INTO TABLE @DATA(result_date_time). out->write( EXPORTING data = result_date_time name = 'RESULT_DATE_TIME' ). ********************************************************************* DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /dmo/travel FIELDS total_price, currency_code, currency_conversion( amount = total_price, source_currency = currency_code, target_currency = 'EUR', exchange_rate_date = @today ) AS total_price_EUR WHERE customer_id = '000001' AND currency_code <> 'EUR' INTO TABLE @DATA(result_currency). out->write( EXPORTING data = result_currency name = 'RESULT__CURRENCY' ). ********************************************************************** SELECT FROM /dmo/connection FIELDS distance, distance_unit, unit_conversion( quantity = CAST( distance AS QUAN ), source_unit = distance_unit, target_unit = CAST( 'MI' AS UNIT ) ) AS distance_MI WHERE airport_from_id = 'FRA' INTO TABLE @DATA(result_unit). out->write( EXPORTING data = result_unit name = 'RESULT_UNIT' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。

ABAP SQL での特別な組込関数の使用

この演習問題では、フライト期間の計算と通貨換算をデータベースにプッシュダウンします。

テンプレート:

  • /LRN/CL_S4D401_DBS_PUSH_DOWN (グローバルクラス)

ソリューション:

  • /LRN/CL_S4D401_DBS_FUNCTIONS (グローバルクラス)

タスク 1: テンプレートのコピー (オプション)

テンプレートクラス /LRN/CL_S4D401_DBS_PUSH_DOWN をコピーします。前の演習問題を完了した場合は、このタスクをスキップし、クラス ZCL_##_SOLUTION の編集を続行することができます。

ステップ

  1. クラス /LRN/CL_S4D401_DBS_PUSH_DOWN を各自のパッケージのクラスにコピーします (推奨名: ZCL_##_SOLUTION、## はグループ番号)。

    1. Project Explorer で、クラス /LRN/CL_S4D401_DBS_PUSH_DOWN を右クリックしてコンテキストメニューを開きます。

    2. コンテキストメニューから Duplicate.... を選択します。

    3. Package 項目にパッケージの名称を入力します。Name 項目に、ZCL_##_SOLUTION (## はグループ番号) と入力します。

    4. Next を選択します。

    5. 移送依頼を確認し、Finish を選択します。

  2. コピーを有効化します。

    1. Ctrl + F3 を押してクラスを有効化します。

タスク 2: タイムスタンプによる計算

ローカルクラス LCL_PASSENGER_FLIGHT で、メソッド CLASS_CONSTRUCTOR の実装を調整します。フライト期間の計算を SELECT 文の項目一覧に移動し、内部テーブル connections_bufferの duration 列に結果を保存します。

ステップ

  1. ローカルクラス LCL_PASSENGER_FLIGHT で、メソッド CLASS_CONSTRUCTOR の実装にナビゲートします。

    1. 前と同じ方法でこのステップを実行します。

  2. SELECT 文の項目一覧の最後に、2 つのタイムスタンプ間の差異 (秒) を計算する適切な SQL 関数への呼出を追加します。

    1. コードを以下のように調整します。

      ABAP
      12345678910111213
      SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( ) INTO TABLE @connections_buffer.
  3. 最初の引数 (パラメータ tstmp1) として、現在日付、出発空港の出発時刻およびタイムゾーンに基づいてタイムスタンプを計算する適切な SQL 関数を呼び出します。

    ヒント

    SELECT 命令で現在日付にアクセスできるように、SELECT 命令の前に関数メソッド cl_abap_context_info=>get_system_date への呼出を移動する必要があります。
    1. コードを以下のように調整します。

      ABAP
      1234567891011121314151617181920
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), ) INTO TABLE @connections_buffer.
  4. 2 番目の引数 (パラメータ tstmp2) と同じ到着タイムスタンプを計算するために、同じ SQL 関数を呼び出します。

    1. コードを以下のように調整します。

      ABAP
      123456789101112131415161718192021222324
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ) INTO TABLE @connections_buffer.
  5. 秒単位ではなく分単位で期間を設定する必要があるため、秒数を 60 で割ります。

    ヒント

    除算の結果を整数として返す適切な算術 SQL 関数を使用します。
    1. コードを以下のように調整します。

      ABAP
      1234567891011121314151617181920212223242526
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, div( tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ), 60 ) INTO TABLE @connections_buffer.
  6. 最後に、完全な式のエイリアス名を指定します (推奨名: duration)。

    1. コードを以下のように調整します。

      ABAP
      1234567891011121314151617181920212223242526
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, div( tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ), 60 ) AS duration INTO TABLE @connections_buffer.
  7. 計算を SELECT 文に正常に移動したので、内部テーブル connections_buffer に対するループ全体を削除するか、コメントします。

    1. LOOP 命令、ENDLOOP 命令、およびその間のすべてのコード行をマークし、Ctrl + < を押してコードの各行の前にコメント文字を挿入します。

タスク 3: 通貨換算

ローカルクラス LCL_PASSENGER_FLIGHT で、メソッド CONSTRUCTOR および GET_FLIGHTS_BY_CARRIER の実装を調整します。通貨換算を SELECT 文の項目一覧に移動します。

ステップ

  1. ローカルクラス LCL_PASSENGER_FLIGHT で、CONSTRUCTOR メソッドの実装にナビゲートします。

    1. 前と同じ方法でこのステップを実行します。

  2. フライト価格を属性 currency に保存されている通貨コードに変換するメソッドコールを見つけます。これを分析してから、コード行の先頭にコメント記号を追加します。

    1. 通貨換算は、グローバルクラス cl_exchange_rates のメソッド convert_to_local_currency を呼び出すことで実行されます。

    2. メソッドの呼出をコメント化するには、TRY 命令、ENDTRY 命令、およびその間のすべてのコード行にマークを付け、Ctrl + < を押します。

  3. cl_exchange_rates=>convert_to_local_currency メソッドコールによって価格属性が入力されなくなったため、flight_raw 構造の価格要素の値を価格属性に直接割り当てます。この割当は、コメントアウトしたメソッドコールの直後に追加します。

    注記

    以下のステップでは、flight_raw-price に変換されたフライト価格が含まれていることを確認します。
    1. コードを以下のように調整します。

      ABAP
      1234567891011121314
      * TRY. * cl_exchange_rates=>convert_to_local_currency( * EXPORTING * date = me->flight_date * foreign_amount = flight_raw-price * foreign_currency = flight_raw-currency_code * local_currency = currency * IMPORTING * local_amount = me->price ). * CATCH cx_exchange_rates. * CLEAR price. * ENDTRY. price = flight_raw-price.
  4. SELECT SINGLE 命令まで上にスクロールします。項目一覧で、テーブル項目 PRICE を通貨換算の SQL 関数の呼出に置き換えます。

    1. コードを以下のように調整します。

      ABAP
      123456789101112
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  5. SQL 関数の 4 つの必須パラメータを指定します。換算レート決定日として、フライト日付 (テーブル項目 flight_date) を使用し、金額および元通貨としてテーブル項目 price および currency を使用し、目標通貨として属性 currency を使用します。

    1. コードを以下のように調整します。

      ABAP
      1234567891011121314151617
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  6. オプションパラメータ on_error に適切な値を指定して、以前と同じ動作を取得します。

    ヒント

    パラメータに使用可能な値とその意味については、SQL 関数の文書を参照してください。
    1. グローバルクラス SQL_CURRENCY_CONVERSION で、構造化定数 c_on_error のコンポーネントとして使用可能な値を確認できます。

    2. コードを以下のように調整します。

      ABAP
      12345678910111213141516171819
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  7. 項目一覧で、テーブル項目 currency_codecurrency 属性に置き換えます。

    1. コードが以下のように調整されました。

      ABAP
      1234567891011121314151617181920
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, * currency_code @currency AS currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  8. メソッド GET_FLIGHTS_BY_CARRIER の実装に移動し、そこで SELECT 命令を同じ方法で調整します。

    1. 項目一覧の最後の 2 つの要素 (価格および通貨コード) をクリップボードにコピーします。

    2. メソッド GET_FLIGHTS_BY_CARRIER の実装に移動します。

    3. SELECT 命令の項目一覧で、最後の 2 つの項目 (price および currency_code) をクリップボードの内容に置き換えます。

    4. コードを以下のように調整します。

      ABAP
      12345678910111213141516
      SELECT FROM /lrn/passflight FIELDS carrier_id, connection_id, flight_date, plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, @currency AS currency_code WHERE carrier_id = @i_carrier_id INTO TABLE @flights_buffer.
  9. グローバルクラスをコンソールアプリとして有効化してテストします。

    1. Ctrl + F3 を押します。

    2. F9 を押します。