標準内部テーブルでは、内容はソートされません。APPEND 文を使用してテーブルに追加する新規エントリは、テーブルの最後に追加されます。

標準内部テーブルのソート
このビデオでは、テーブルをそのキー、任意のフィールド、昇順および降順でソートする方法について説明します。
Objective
標準内部テーブルでは、内容はソートされません。APPEND 文を使用してテーブルに追加する新規エントリは、テーブルの最後に追加されます。

このビデオでは、テーブルをそのキー、任意のフィールド、昇順および降順でソートする方法について説明します。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
TYPES t_flights TYPE STANDARD TABLE OF /dmo/flight
WITH NON-UNIQUE KEY carrier_id connection_id flight_date.
DATA flights TYPE t_flights.
flights = VALUE #( ( client = sy-mandt
carrier_id = 'LH'
connection_id = '0400'
flight_date = '20230201'
plane_type_id = '747-400'
price = '600'
currency_code = 'EUR' )
( client = sy-mandt
carrier_id = 'LH'
connection_id = '0400'
flight_date = '20230115'
plane_type_id = '747-400'
price = '600' currency_code = 'EUR' )
( client = sy-mandt
carrier_id = 'QF'
connection_id = '0006'
flight_date = '20230112'
plane_type_id = 'A380'
price = '1600' currency_code = 'AUD' )
( client = sy-mandt
carrier_id = 'AA'
connection_id = '0017'
flight_date = '20230110'
plane_type_id = '747-400'
price = '600'
currency_code = 'USD' )
( client = sy-mandt
carrier_id = 'UA'
connection_id = '0900'
flight_date = '20230201'
plane_type_id = '777-200'
price = '600'
currency_code = 'USD' )
).
out->write( 'Contents Before Sort' ).
out->write( '____________________' ).
out->write( flights ).
out->write( ` ` ).
* Sort with no additions - sort by primary table key carrier_id connection_id flight_date
SORT flights.
out->write( 'Effect of SORT with no additions - sort by primary table key' ).
out->write( '____________________________________________________________' ).
out->write( flights ).
out->write( ` ` ).
* Sort with field list - default sort direction is ascending
SORT flights BY currency_code plane_type_id.
out->write( 'Effect of SORT with field list - ascending is default direction' ).
out->write( '________________________________________________________________' ).
out->write( flights ).
out->write( ` ` ).
* Sort with field list and sort directions.
SORT flights BY carrier_Id ASCENDING flight_Date DESCENDING.
out->write( 'Effect of SORT with field list and sort direction' ).
out->write( '_________________________________________________' ).
out->write( flights ).
out->write( ` ` ).

場合によっては、内部テーブルから重複エントリを削除する必要があります。たとえば、この例では、carrier_id と connection_id の各組み合わせがテーブルに 1 回だけ表示されます。

命令 DELETE ADJACENT DUPLICATES を使用して、内部テーブルから重複エントリを削除することができます。ただし、この文は、エントリが隣接している (つまり、隣り合っている) 場合にのみ機能します。
DELETE ADJACENT DUPLICATES 命令を使用する前に、重複値をスクリーニングする列 (この場合は carrier_id および connection_id) に従って内部テーブルをソートする必要があります。

ただし、重複するフライト番号が隣り合っている場合でも、このフォームの DELETE ADJACENT DUPLICATES 命令では何も削除されません。これは、基本書式の命令では、重複エントリの識別時にテーブルのすべてのキー項目が考慮され、2 つの LH 0400 接続の値が異なる flight_date であるため、重複エントリとしてカウントされないためです。

carrier_id と connection_id の組合せが同じであるエントリを削除するには、flight_date の値が異なる場合でも、DELETE ADJACENT DUPLICATES 命令の COMPARING オプションを使用する必要があります。ステートメントで COMPARING carrier_id connection_id を使用すると、重複エントリの識別時にこれらの項目のみを考慮するようにシステムに指示することができます。
COMPARING オプションでキー項目と非キー項目の任意の組合せを指定することができますが、最初に同じ項目に従ってテーブルをソートしておく必要があります。
COMPARING ALL FIELDS という追加もあります。これを使用する場合は、重複エントリが識別されるように、2 つのエントリのテーブル行全体が同じである必要があります。
123456789101112131415161718192021222324252627282930313233343536373839
TYPES t_flights TYPE STANDARD TABLE OF /dmo/flight WITH NON-UNIQUE KEY carrier_id connection_id flight_date.
DATA: flights TYPE t_flights.
flights = VALUE #( ( client = sy-mandt carrier_id = 'LH' connection_id = '0400' flight_date = '20230201' plane_type_id = '747-400' price = '600' currency_code = 'EUR' )
( client = sy-mandt carrier_id = 'QF' connection_id = '0006' flight_date = '20230112' plane_type_id = 'A380' price = '1600' currency_code = 'AUD' )
( client = sy-mandt carrier_id = 'AA' connection_id = '0017' flight_date = '20230110' plane_type_id = '747-400' price = '600' currency_code = 'USD' )
( client = sy-mandt carrier_id = 'LH' connection_id = '0400' flight_date = '20230301' plane_type_id = '747-400' price = '600' currency_code = 'EUR' )
( client = sy-mandt carrier_id = 'UA' connection_id = '0900' flight_date = '20230201' plane_type_id = '777-200' price = '600' currency_code = 'USD' )
( client = sy-mandt carrier_id = 'QF' connection_id = '0006' flight_date = '20230210' plane_type_id = 'A380' price = '1600' currency_code = 'AUD' ) ).
out->write( 'Contents Before DELETE ADJACENT DUPLICATES' ).
out->write( '____________________' ).
out->write( flights ).
out->write( ` ` ).
DELETE ADJACENT DUPLICATES FROM flights.
out->write( 'Contents after DELETE ADJACENT DUPLICATES' ).
out->write( 'Nothing deleted - key values are not adjacent' ).
out->write( 'Sort the table before DELETE ADJACENT DUPLICATES').
out->write( flights ).
out->write( ` ` ).
SORT flights BY carrier_id connection_id flight_date.
DELETE ADJACENT DUPLICATES FROM flights.
out->write( 'Contents after DELETE ADJACENT DUPLICATES' ).
out->write( 'Nothing deleted - ABAP compares all key values including flight_date, which is different for every entry' ).
out->write( flights ).
out->write( ` ` ).
DELETE ADJACENT DUPLICATES FROM flights COMPARING carrier_id connection_id.
out->write( 'Contents after DELETE ADJACENT DUPLICATES with COMPARING and field list' ).
out->write( 'Entries with identical values of carrier_id and connection_id have been deleted' ).
out->write( flights ).多くの場合、内部テーブルに別の内部テーブルの値を入力する必要があります。1 つのテーブルから別のテーブルにデータをコピーする単純な問題である場合があります。また、ターゲットテーブルに書き込むために複数のソーステーブルからデータを読み込み、値を計算するために式を使用する必要が生じることもあります。

ABAP は、これらのタスクを実行するための手段を提供します。1 つのテーブルから別のテーブルにデータをコピーするだけの場合は、式 CORRESPONDING #( ) を使用できます。より複雑な操作では、テーブル理解を使用することができます。
2 つの内部テーブルの同じ名称の項目間でデータをコピーするには、CORRESPONDING 演算子を使用します。これは、構造の CORRESPONDING と同様に機能します。ソース内部テーブルの行ごとに、ターゲット内部テーブルに新規行が登録され、同じ名称の項目間でデータがコピーされます。ターゲットに同じ名称の項目がないソース項目はコピーされません。ソースに同じ名称の項目がないターゲット項目には、データ型固有の初期値が入力されます。

この例では、ソーステーブルキャリアに 3 つの行が含まれています。したがって、値割当後は、ターゲットの内部テーブル接続にも 3 つの行が含まれます。
項目 carrier_id と carrier_name が両方の内部テーブルに存在します。これらはソースからターゲットにコピーされます。項目 currency_code はソースにのみ存在します。これはコピーされません。項目 connection_id、airport_from_id、および airport_to_id はターゲットにのみ存在します。初期値が入力されます。
注記:
割当前にターゲット内部テーブルにデータが含まれている場合、そのデータは削除されます。

次に、より複雑な例を考えてみましょう。プログラムには、フライト接続を含む内部テーブルと、空港の名称と場所を含む内部テーブルがあります。3 番目の内部テーブルには、接続テーブルの carrier_id、connection_id、および airport_from_id と、空港テーブルの空港 name を入力する必要があります。これは、テーブル理解を使用して行うことができます。

ある内部テーブルに別の内部テーブルを書き込むには、VALUE演算子に FOR 式を使用します。FOR は、ソーステーブルに対するループを実装し、各行を変数行に順次配置します。括弧内で、構文 component = VALUE を使用して新しい行のコンポーネントに値を割り当てます。これは、VALUE #( ) を使用して構造に書き込むときに使用する構文とまったく同じです。

以下は、この例のコードです。FOR line IN connections は connections テーブルを反復し、各行を変数行に順次配置します。括弧内で、テーブル result_table の各新規行を作成します。式の左側には result_table の列があり、右側には式に割り当てる値があります。列 carrier_id、connection_id、および departure_airport は、それぞれ行のコンポーネント carrier_id、connection_id、および airport_from_id を使用して入力されます。列 departure_airport_name に入力するには、テーブル式を使用して、行のコンポーネント airport_from_id を空港キーとして使用し、内部テーブルの空港で空港名を検索します。

WHERE を使用して論理条件 (特定の航空会社の接続のみなど) を指定するか、オプション FROM および TO を使用して行の範囲を指定することで、ソーステーブルでの反復を制限することができます。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
TYPES: BEGIN OF t_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
departure_airport TYPE /dmo/airport_from_id,
departure_airport_Name TYPE /dmo/airport_Name,
END OF t_connection.
TYPES t_connections TYPE STANDARD TABLE OF t_connection WITH NON-UNIQUE KEY carrier_id connection_id.
DATA connections TYPE TABLE OF /dmo/connection.
DATA airports TYPE TABLE OF /dmo/airport.
DATA result_table TYPE t_connections.
* Aim of the method:
* Read a list of connections from the database and use them to fill an internal table result_table.
* This contains some data from the table connections and adds the name of the departure airport.
SELECT FROM /dmo/airport FIELDS * INTO TABLE @airports.
SELECT FROM /dmo/connection FIELDS * INTO TABLE @connections.
out->write( 'Connection Table' ).
out->write( '________________' ).
out->write( connections ).
out->write( ` ` ).
* The VALUE expression iterates over the table connections. In each iteration, the variable line
* accesses the current line. Inside the parentheses, we build the next line of result_table by
* copying the values of line-carrier_Id, line-connection_Id and line-airport_from_id, then
* loooking up the airport name in the internal table airports using a table expression
result_table = VALUE #( FOR line IN connections ( carrier_Id = line-carrier_id
connection_id = line-connection_id
departure_airport = line-airport_from_id
departure_airport_name = airports[ airport_id = line-airport_from_id ]-name ) ).
out->write( 'Results' ).
out->write( '_______' ).
out->write( result_table ).

内部テーブルを反復処理するときに、たとえば合計やローカウントを生成するために、情報の要約が必要になることがあります。

最も単純な削減形式は、内部テーブルで反復し、基本値を返します。減少の INIT 部分で可変合計が定義されます。変数の合計の型は、合計の型と互換性がある必要があります。FOR line IN flights は、各行が作業領域行に順次配置される内部テーブルフライトの反復です。NEXT 式では、各行の seats_occupied の内容が変数 total に追加されます。反復の最後に、合計の内容が変数の合計に割り当てられます。
注記

削減の戻り値には、構造化データ型を含めることもできます。この例では、タイプ t_results は、占有されたコンポーネントと最大コンポーネントを含む構造です。削減の INIT セクションで、タイプ t_results の変数合計を宣言します。NEXT 式では、占有コンポーネントと最大コンポーネントをアドレス指定し、内部テーブル全体の各コンポーネントの合計をコンパイルします。
ターゲット変数のデータ型と REDUCE 式の結果のデータ型は互換性がある必要があります。

戻り値があるだけでなく、REDUCE 式でも追加のローカル変数を使用できます。この例では、式の INIT セクションに、戻り値を含む totals_avg と count の 2 つのデータ宣言が含まれています。count は整数値 1 で宣言されているため、型 I が割り当てられます。式の count セクションで NEXT を使用します。反復ごとに、これを使用してこれまでのすべてのフライトの平均占有率を計算し、各反復の最後に値に 1 を加算します。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
TYPES: BEGIN OF t_results,
occupied TYPE /dmo/plane_seats_occupied,
maximum TYPE /dmo/plane_seats_max,
END OF t_results.
TYPES: BEGIN OF t_results_with_Avg,
occupied TYPE /dmo/plane_seats_occupied,
maximum TYPE /dmo/plane_seats_max,
average TYPE p LENGTH 16 DECIMALS 2,
END OF t_results_with_avg.
DATA flights TYPE TABLE OF /dmo/flight.
SELECT FROM /dmo/flight FIELDS * INTO TABLE @flights.
* Result is a scalar data type
DATA(sum) = REDUCE i( INIT total = 0 FOR line IN flights NEXT total += line-seats_occupied ).
out->write( 'Result is a scalar data type' ).
out->write( '_____________ ______________' ).
out->write( sum ).
out->write( ` ` ).
* Result is a structured data type
DATA(results) = REDUCE t_results( INIT totals TYPE t_results
FOR line IN flights NEXT totals-occupied += line-seats_occupied
totals-maximum += line-seats_max ).
out->write( 'Result is a structure' ).
out->write( '_____________________' ).
out->write( results ).
out->write( ` ` ).
* Result is a structured data type
* Reduction uses a local helper variable
* Result of the reduction is always the *first* variable declared after init
out->write( 'Result is a structure. The average is calculated using a local helper variable' ).
out->write( '______________________________________________________________________________' ).
DATA(result_with_Average) = REDUCE t_results_with_avg( INIT totals_avg TYPE t_results_with_avg count = 1
FOR line IN flights NEXT totals_Avg-occupied += line-seats_occupied
totals_avg-maximum += line-seats_max
totals_avg-average = totals_avg-occupied / count
count += 1 ).
out->write( result_with_average ).
ローカルクラス LCL_PASSENGER_FLIGHT のメソッド GET_FLIGHTS_BY_CARRIER で、メソッド呼出ごとにバッファがリフレッシュされます。この演習問題では、メソッドの実装を調整して、すでにバッファされたフライトデータを保持します。
ローカルクラス LCL_CARRIER のメソッド GET_AVERAGE_FREE_SEATS では、データベースの集計もテーブル削減に置き換えます。