コードの分析およびテスト
データ型およびデータ型変換の正しい使用
文字項目の処理
ABAP SQL でのコードプッシュダウンの使用
内部テーブルのパフォーマンスの改善
権限チェックの実装
効果的なオブジェクト指向コードの設計
例外クラスの定義と処理
ABAP コードへの文書の追加

ABAP SQL でのデータセットのソートおよび圧縮

Objectives

After completing this lesson, you will be able to:
  • ソートされた結果セットをデータベースに要求します。
  • 圧縮および集計されたデータセットを取得します。

ソートされた結果セット

このビデオでは、SELECT 文の結果セットをソートする方法を学習します。

試してみる: ORDER BY

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    123456789101112131415161718
    SELECT FROM /dmo/flight FIELDS carrier_id, connection_id, flight_date, seats_max - seats_occupied AS seats WHERE carrier_id = 'AA' AND plane_type_id = 'A320-200' * ORDER BY seats_max - seats_occupied DESCENDING, * flight_date ASCENDING INTO TABLE @DATA(result). out->write( EXPORTING data = result name = 'RESULT' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。
  5. ORDER BY オプションのある行のスター記号 (*) を削除し、再度有効化します。
  6. を再度実行し、コンソール出力のソート順序がどのように変更されたかを確認します。
  7. ORDER BY オプションを使用してください。ソート方向を変更し、他の項目または式で結果をソートして、構文について理解します。

一意の結果セット

DISTINCT オプションを使用すると、SELECT 文の結果セットから重複を削除できます。追加は、項目一覧の最初のエレメントの直前に配置する必要があります。

その方法については、このビデオを視聴してください。

試してみる: SELECT DISTINCT

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    12345678910111213141516
    SELECT FROM /dmo/connection FIELDS * DISTINCT airport_from_id, distance_unit ORDER BY airport_from_id INTO TABLE @DATA(result). out->write( EXPORTING data = result name = 'RESULT' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。
  5. DISTINCT オプションのある行のスター記号 (*) を削除し、再度有効化します。
  6. を再度実行し、コンソール出力がどのように変更されたかを確認します。

集約関数

集計式は、結果セットの複数の行に対して集計関数を呼び出すことで、sql_expression (sql_exp) から単一の値を計算します。

重要な集計関数には、次のようなものがあります。

  • SUM( sql_exp )

    行セット内の SQL 式 sql_exp の結果の合計を決定します。結果セットのデータ型は、SQL 式のデータ型です。SQL 式 sql_exp の結果タイプは数値型である必要があります。

  • MIN( sql_exp ) および MAX( sql_exp )

    行セット内の SQL 式 sql_exp の結果の最大値または最小値を決定します。結果のデータ型は、SQL 式の結果のデータ型です。

    SQL 式 sql_exp の結果は数値型である必要があります。式に 1 つの列が指定されている場合は、その列のデータ型も指定できます。

  • AVG( sql_exp [ AS dtype ] )

    行セット内の SQL 式 sql_exp の内容の平均値を決定します。10 進浮動小数点数の結果の暗黙的なデータ型は、対応するデータ型 (DECFLOAT16、DECFLOAT34、DF16_DEC、または DF34_DEC) です。それ以外の場合は、データ型 FLTP またはオプション AS dtype によって決定されます。

  • COUNT( * ) または COUNT(*)

    2 つの綴りは同じ意味を持ち、行セット内の行数を生成します。ほとんどの場合、結果データ型は INT4 です。COUNT( * ) または COUNT(*) が項目一覧の唯一のエレメントである場合、結果タイプは INT8 です。

  • COUNT( DISTINCT sql_exp )

    ローセット内の SQL 式 sql_exp の結果の固有値の数を決定します。結果のデータ型は INT4 です。

項目一覧の集約機能のみ

SELECT 命令の項目一覧に集約関数以外が含まれていない場合、結果セットは常に 1 つの行で構成されます。これは、集計が空のデータセットに基づいている場合にも該当します。

この例では、左側の SELECT 文は、右側の SELECT の集約の基準となるデータセットを示しています。

列 DISTANCE の最大値は 6217、最小値は 6162 であることがわかります。行の合計数は 4 で、列 AIRPORT_FROM_ID には 3 つの固有値が含まれています (値 'FRA' が 2 回表示されます)。

試してみる: 集約関数

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    1234567891011121314151617181920212223242526272829303132333435
    SELECT FROM /dmo/connection FIELDS carrier_id, connection_id, airport_from_id, distance WHERE carrier_id = 'LH' INTO TABLE @DATA(result_raw). out->write( EXPORTING data = result_raw name = 'RESULT_RAW' ). ********************************************************************* SELECT FROM /dmo/connection FIELDS MAX( distance ) AS max, MIN( distance ) AS min, SUM( distance ) AS sum, AVG( distance ) AS average, COUNT( * ) AS count, COUNT( DISTINCT airport_from_id ) AS count_dist WHERE carrier_id = 'LH' INTO TABLE @DATA(result_aggregate). out->write( EXPORTING data = result_aggregate name = 'RESULT_AGGREGATED' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。

GROUP BY オプション

SELECT 文の項目一覧に集約関数と他の要素 (列、式など) が混在している場合、SQL の構文には GROUP BY 句が必要です。GROUP BY 句では、集計の外部の項目一覧に表示されるすべての列を一覧表示する必要があります。

右側の SELECT 命令では、項目一覧で CARRIER_ID と DISTANCE の 2 つの列が使用されます。列 DISTANCE は、集約関数の入力としてのみ表示されるため、GROUP BY の後では必要ありません。ただし、列 CARRIER_ID は集約関数の外部で使用されているため、GROUP BY の後に一覧表示する必要があります。

GROUP BY の影響は、SELECT 文の結果で確認できます。集計が実行されるデータセットは、GROUP BY 項目の同じ値を持つサブセット (グループ) に分割されます。最終結果セットには、グループごとに 1 つのローが含まれます。集計式は、グループごとに個別に評価されます。

たとえば、CARRIER_ID = 'AA' の行には COUNT = 5 および MAX = 4156 が含まれます。これは、CARRIER_ID = 'AA' のサブセットに 5 つの行が含まれており、このサブセット内の距離の最大値は 4156 であるためです。

試してみる: GROUP BY

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいグローバルクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    123456789101112131415161718
    SELECT FROM /dmo/connection FIELDS * carrier_id, MAX( distance ) AS max, MIN( distance ) AS min, SUM( distance ) AS sum, COUNT( * ) AS count * GROUP BY carrier_id INTO TABLE @DATA(result). out->write( EXPORTING data = result name = 'RESULT' ).
  3. CTRL + F3 を選択してクラスを有効化し、F9 を選択してコンソールアプリとして実行します。
  4. コンソール出力を分析します。
  5. キーワード FIELDS (項目名 carrier_id の行) の後の行のスター記号 (*) を削除します。GROUP BY 句に項目 CARRIER_ID がないことを通知する構文エラーに注意してください。
  6. GROUP BY オプションを含む行から星記号 (*) を削除し、再度有効化します。
  7. を再度実行し、コンソール出力がどのように変更されたかを確認します。

ソートおよび集計データのリトリーブ

この演習問題では、日付別にフライトをソートし、データベースにおけるフライトの平均占有率を計算します。

テンプレート:

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

ソリューション:

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

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

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

ステップ

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

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

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

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

    4. Next を選択します。

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

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

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

タスク 2: データのソート

ローカルクラス LCL_PASSENGER_FLIGHT で、メソッド GET_FLIGHTS_BY_CARRIER の実装を調整します。適切な指示を追加して、フライト日付別に昇順で順序付けられたフライトの一覧を取得します。次に、ローカルクラス LCL_CARGO_FLIGHT でも同じ処理を行います。

ステップ

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

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

  2. SELECT 文を調整して、フライト日付で昇順にソートされた結果がデータベースから返されるようにします。

    1. INTO 句の前に ORDER BY 句を追加します。

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

      ABAP
      1234567891011121314151617
      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 ORDER BY flight_date ASCENDING INTO TABLE @flights_buffer.
  3. ローカルクラス LCL_CARGO_FLIGHT のメソッド GET_FLIGHTS_BY_CARRIER にナビゲートします。

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

  4. SELECT 文を調整して、フライト日付で昇順にソートされた結果がデータベースから返されるようにします。

    1. INTO 句の前に ORDER BY 句を追加します。

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

      ABAP
      12345678
      SELECT FROM /lrn/cargoflight FIELDS carrier_id, connection_id, flight_date, plane_type_id, maximum_load, actual_load, load_unit, airport_from_id, airport_to_id, departure_time, arrival_time WHERE carrier_id = @i_carrier_id ORDER BY flight_date ASCENDING INTO CORRESPONDING FIELDS OF TABLE @flights_buffer.

タスク 3: 集計関数の使用

ローカルクラス LCL_CARRIER で、メソッド GET_AVERAGE_FREE_SEATS の実装を調整します。すべての乗客フライトのループで結果を計算する代わりに、データベーステーブル /LRN/PASSFLIGHT の SELECT を使用して計算を行います。

ステップ

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

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

  2. メソッド実装のソースコードを削除またはコメントします。

    1. METHOD get_average_free_seats. 命令と ENDMETHOD. 命令の間のコードをマークし、Ctrl + < を押します。

  3. ここで、現在の航空会社の空席と乗客フライト数の合計を取得する SELECT 文を実装します。これは、carrier_id 属性に保存されます。インライン宣言データオブジェクト (推奨名: aggregates) に結果を格納します。

    1. 以下のコードを追加します。

      ABAP
      12345
      SELECT FROM /lrn/passflight FIELDS SUM( seats_max - seats_occupied ) AS sum, COUNT(*) AS count WHERE carrier_id = @carrier_id INTO @DATA(aggregates).
  4. SELECT 文の後、2 つの集約の比率を計算し、その結果をリターンパラメータ r_result に割り当てます。

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

      ABAP
      1234567
      SELECT FROM /lrn/passflight FIELDS SUM( seats_max - seats_occupied ) AS sum, COUNT(*) AS count WHERE carrier_id = @carrier_id INTO @DATA(aggregates). r_result = aggregates-sum / aggregates-count.

      注記

      GET_AVERAGE_FREE_SEATS メソッドをさらに簡潔に実装するには、以下のコードを使用します。
      ABAP
      1234
      SELECT FROM /lrn/passflight FIELDS CAST( AVG( seats_max - seats_occupied ) AS INT4 ) WHERE carrier_id = @carrier_id INTO @r_result.
  5. グローバルクラスをコンソールアプリとして有効化してテストします。

    1. Ctrl + F3 を押します。

    2. F9 を押します。