You realize that in method GET_FLIGHTS_BY_CARRIER, you refresh the buffer whenever the method is called for a new carrier ID. In this exercise, you adjust the method implementation to keep already buffered flight data.
You also replace the aggregation on the database with a table reduction.
Task 1: Copy Template (Optional)
Copy the template class. If you finished the previous exercise, you can skip this task and continue editing your class ZCL_##_SOLUTION.
Steps
Copy class /LRN/CL_S4D401_DBS_AGGREGATE to a class in your own package (suggested name: ZCL_##_SOLUTION, where ## stands for your group number).
In the Project Explorer view, right-click class /LRN/CL_S4D401_DBS_AGGREGATE to open the context menu.
From the context menu, choose Duplicate ....
Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_SOLUTION, where ## stands for your group number.
Adjust the description and choose Next.
Confirm the transport request and choose Finish.
Activate the copy.
Press Ctrl + F3 to activate the class.
Task 2: Append the Flights Buffer
Change the implementation of method GET_FLIGHTS_BY_CARRIER in local class LCL_PASSENGER_FLIGHT. Make sure, that when you read flight data from the database, you add the data to the buffer (static attribute flight_buffer), rather than replacing the current content. In a first approach, add the new entries in any case, then remove the duplicates. In a second approach, skip the SELECT statement, if the buffer already contains flights of the requested airline.
Steps
In local class LCL_PASSENGER_FLIGHT, navigate to the implementation of method GET_FLIGHTS_BY_CARRIER.
Perform this step as in previous exercises.
Adjust the loop over static attribute flight_buffer. Add a filter that only reads the flights from the airline specified in importing parameter i_carrier_id.
Adjust the code as follows:
1234
LOOP AT flights_buffer INTO DATA(flight)
WHERE carrier_id = i_carrier_id.
Adjust the SELECT statement to make sure the result is added to the content of internal table flights_buffer instead of replacing the current content.
Hint
Replace the INTO TABLE clause with an APPENDING TABLE clause.In the SELECT statement, replace INTO with APPENDING.
Adjust the code as follows:
12345678910111213141516171819
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.
APPENDING TABLE @flights_buffer.
After the SELECT statement, add a statement that removes duplicate entries from internal table flights_buffer.
After the SELECT statement, add the following code:
12345
SORT flights_buffer BY carrier_id connection_id flight_date.
DELETE ADJACENT DUPLICATES FROM flights_buffer
COMPARING carrier_id connection_id flight_date.
Now that you sort the contents of flights_buffer after every SELECT APPENDING, you can omit the redundant sorting on the database.
In the SELECT statement, remove or comment the ORDER BY clause.
Activate and test your global class as console app.
Press Ctrl + F3.
Press F9.
Now adjust the logic. Instead of removing the duplicates, skip the SELECT statement if flights_buffer already contains flights for the requested airline.
Comment the DELETE statement you just added.
Surround the SELECT statement and the SORT statement with IF … ENDIF.
In the IF statement, use predicate function line_exists to ensure that flights_buffer does not contain any rows with carrier_id = i_carrier_id.
Adjust the code as follows:
12345678910111213141516171819202122232425
IF NOT line_exists( flights_buffer[ carrier_id = i_carrier_id ] ).
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.
APPENDING TABLE @flights_buffer.
SORT flights_buffer BY carrier_id connection_id flight_date.
* DELETE ADJACENT DUPLICATES FROM flights_buffer
* COMPARING carrier_id connection_id flight_date.
ENDIF.
Activate and test your global class as console app.
Press Ctrl + F3.
Press F9.
Task 3: Use a Table Comprehension
Change the implementation of method GET_FLIGHTS_BY_CARRIER in local class LCL_PASSENGER_FLIGHT. Replace the loop over static attribute flights_buffer with a table comprehension, that is, directly fill the result parameter r_result with a VALUE expression.
Steps
In local class LCL_PASSENGER_FLIGHT, navigate to the implementation of method GET_FLIGHTS_BY_CARRIER.
Perform this step as before.
Comment the LOOP … ENDLOOP block at the end of the method implementation.
Select the code rows with LOOP and ENDLOOP and all code rows between them and press Ctrl + < to insert a comment sign at the beginning of each selected row.
Your code should look like this:
12345678910
* LOOP AT flights_buffer INTO DATA(flight)
* WHERE carrier_id = i_carrier_id.
*
* APPEND NEW lcl_passenger_flight( i_carrier_id = flight-carrier_id
* i_connection_id = flight-connection_id
* i_flight_date = flight-flight_date )
* TO r_result.
* ENDLOOP.
Implement a VALUE expression and assign the result to returning parameter r_result..
Add the following code:
12345
r_result = VALUE #(
).
Inside the expression, add a loop over internal table flights_buffer and add a new row to the result (suggested name for the work area: flight).
Adjust the code as follows:
1234567
r_result = VALUE #(
FOR flight IN flights_buffer
(
)
).
Add a filter condition to ensure that only flights of the requested airline are processed.
Note
Remember to surround the condition with an extra pair of brackets.Adjust the code as follows:
12345678
r_result = VALUE #(
FOR flight IN flights_buffer
WHERE ( carrier_id = i_carrier_id )
(
)
).
Fill each row of the result with a new instance of class LCL_PASSENGER_FLIGHT. Supply the constructor with information from the current row of flights_buffer, that is, from the work area flight).
Adjust the code as follows:
12345678910111213
r_result = VALUE #(
FOR flight IN flights_buffer
WHERE ( carrier_id = i_carrier_id )
(
NEW lcl_passenger_flight(
i_carrier_id = flight-carrier_id
i_connection_id = flight-connection_id
i_flight_date = flight-flight_date
)
)
).
Activate and test your global class as console app.
Press Ctrl + F3.
Press F9.
Task 4: Use a Table Reduction
In local class LCL_CARRIER, adjust the implementation of method GET_AVERAGE_FREE_SEATS. Instead of calculating the result in a SELECT statement, use a table reduction to extract the result from the instances that are stored in internal table passenger_flights.
Steps
In local class LCL_CARRIER, navigate to the implementation of method GET_AVERAGE_FREE_SEATS.
Perform this step as before.
Delete or comment the source code of the method implementation.
Mark the code between statements METHOD get_average_free_seats. and ENDMETHOD. and press Ctrl + <.
Implement a REDUCE expression and assign the result to returning parameter r_result..
Add the following code:
12345
r_result = REDUCE #(
).
Inside the expression, declare and initialize a temporary variable with value 0 (suggested name: i).
Adjust the code as follows:
12345
r_result = REDUCE #(
INIT i = 0
).
Before the closing bracket of the expression, add a loop over internal table passenger_flights (suggested name for the work area: flight).
Adjust the code as follows:
123456
r_result = REDUCE #(
INIT i = 0
FOR flight IN passenger_flights
).
In each iteration, add the number of free seats of the current LCL_PASSENGER_FLIGHT instance to the temporary variable.
Adjust the code as follows:
1234567
r_result = REDUCE #(
INIT i = 0
FOR flight IN passenger_flights
NEXT i = i + flight->get_free_seats( )
).
Note
Alternatively, you can use an assignment expression like this:NEXT i += flight->get_free_seats( )
Expand
Finally, calculate the average. Divide the total number of free seats (that is, the result of the table reduction) by the number of entries in passenger_flights .
Adjust the code as follows:
12345678
r_result = REDUCE #(
INIT i = 0
FOR flight IN passenger_flights
NEXT i = i + flight->get_free_seats( )
)
/ lines( passenger_flights ).
Activate and test your global class as console app.
Press Ctrl + F3.
Press F9.