Skip to content

Lesson 7 Practice — Booking Statistics with Aggregation ​

The guided lesson summarized:

text
/DMO/FLIGHT

Now summarize:

text
/DMO/BOOKING

Your goal is to answer:

For each carrier and currency, how many bookings exist and what do their flight-price values look like?

The architecture is:

text
/DMO/BOOKING
      ├──► ZI_BOOKING_STATS_###
      └──► ZI_BOOKING_HEAVY_###
                    ↓
                  Reader
                    ↓
                  Runner

You will also create a second grouped CDS View Entity that uses:

text
HAVING

to keep only sufficiently large booking groups.


Objects to create ​

text
ZI_BOOKING_STATS_###
ZI_BOOKING_HEAVY_###
ZCL_BOOKING_STATS_READER_###
ZCL_CDS_L07_P_###

Replace ### with your own suffix.


Part 1 — Inspect /DMO/BOOKING ​

Open Data Preview for:

text
/DMO/BOOKING

Find at least:

text
travel_id
booking_id
carrier_id
connection_id
flight_date
flight_price
currency_code

Answer:

What does one /DMO/BOOKING row represent? ​

What are the table key fields? ​


Part 2 — Define the output grain before writing CDS ​

Your summary should contain one row for each:

text
CarrierId + CurrencyCode

Write this sentence before coding:

text
One result row represents:
____________________________________________

Do not continue until the grouping requirement is clear.


Part 3 — Explain why CurrencyCode is part of the group ​

Consider:

text
100 EUR
200 USD

Answer:

Why would a total of 300 be semantically incomplete? ​

Why does grouping by currency solve the basic exercise? ​

Does grouping by currency perform currency conversion? ​


Part 4 — Create ZI_BOOKING_STATS_### ​

Create a Data Definition:

text
Name:        ZI_BOOKING_STATS_###
Description: Booking Statistics

Use a modern CDS View Entity.

Do not use obsolete:

text
legacy generated SQL-view-name annotation

Part 5 — Required grouping dimensions ​

Expose:

text
CarrierId
CurrencyCode

Use the source fields:

text
carrier_id
currency_code

Both dimensions must participate in GROUP BY.


Part 6 — Add BookingCount ​

Create:

text
BookingCount

using:

text
COUNT(*)

Answer:

What exactly does the count represent for one result row?


Part 7 — Add total booking value ​

Create:

text
TotalBookingValue

using:

text
SUM(flight_price)

Preserve the semantic relationship to:

text
CurrencyCode

using the amount/currency annotation learned in Lesson 6.


Part 8 — Transfer the AVG rule without mixing in currency complexity ​

You already implemented AVG safely in the guided Flight view using the numeric field:

text
seats_occupied

Before continuing, write the correct CDS expression from memory for:

text
average occupied seats with two decimal places

Then verify it against ZI_FLIGHT_STATS_###.

Answer:

Why does CDS require an explicit result type for AVG? ​

Why are we not making AVG( flight_price ) part of the required Booking solution? ​

Use these ideas:

text
amount semantics
currency context
keep the practice focused

Part 9 — Add minimum and maximum ​

Create:

text
LowestBookingValue
HighestBookingValue

using:

text
MIN
MAX

Preserve the amount/currency semantics for both.


Part 10 — Write GROUP BY ​

Your grouping must match the intended output grain.

Do not group by:

text
TravelId
BookingId

because that would make the groups too detailed.

Do not use the current select-list aliases in place of the source fields.


Part 11 — Activate and preview ​

Run:

text
Ctrl + F2
Ctrl + F3
F8

Inspect several result rows.

For each row, verify mentally:

text
CarrierId
CurrencyCode
BookingCount
TotalBookingValue

Part 12 — Check that currencies remain separate ​

Look for a carrier that may have more than one currency in the demo data.

If present, confirm that it produces separate rows such as:

text
Carrier A + EUR
Carrier A + USD

rather than one combined monetary total.

If your current Trial data does not contain such a carrier, explain what the model would do if it did.


Part 13 — Create a HAVING view ​

Create:

text
ZI_BOOKING_HEAVY_###

Requirements:

text
one row per CarrierId + CurrencyCode
BookingCount
TotalBookingValue

Keep only groups with at least:

text
2 bookings

Use:

text
HAVING

not an upper CDS layer for this exercise.


Part 14 — Explain the HAVING condition ​

Write the condition in plain language:

text
First ______________________________________
Then  ______________________________________
Finally ____________________________________

Use these concepts:

text
group
count
filter groups

Part 15 — Change the threshold experimentally ​

Preview with a threshold of:

text
2

Then try a larger threshold.

Record:

text
Threshold:
Result group count:

Restore the course threshold when finished.

The exact data depends on your Trial system.


Part 16 — Compare WHERE and HAVING ​

Complete:

QuestionWHEREHAVING
Filters individual source rows?
Filters grouped result?
Happens before grouping?
Happens after aggregation?
Can directly contain aggregate expressions for this purpose?

Part 17 — Reader ​

Create:

text
ZCL_BOOKING_STATS_READER_###

Add public table types based on:

text
ZI_BOOKING_STATS_###
ZI_BOOKING_HEAVY_###

Create:

text
GET_ALL
GET_HEAVY

Requirements:

  • GET_ALL returns all carrier/currency statistics;
  • GET_HEAVY returns only the groups kept by the HAVING view;
  • use ABAP SQL against the CDS entities;
  • sort both results by CarrierId, then CurrencyCode;
  • do not select directly from /DMO/BOOKING in the Reader.

Part 18 — Runner ​

Create:

text
ZCL_CDS_L07_P_###

Implement:

text
IF_OO_ADT_CLASSRUN

The Runner should:

  1. call GET_ALL;
  2. print a heading and all grouped statistics;
  3. call GET_HEAVY;
  4. print a second heading and only the groups that passed HAVING.

The Runner must not contain manual aggregation loops.

Compare the two outputs and explain what the HAVING view removed.


Part 19 — Code-pushdown explanation ​

Compare:

text
A)
SELECT all bookings
→ ABAP LOOP
→ manual grouping
→ manual totals

with:

text
B)
CDS GROUP BY / aggregates
→ ABAP receives summary rows

Explain at least three reasons why B is a better model for this requirement.

Do not write:

CDS is always faster.

Use a more precise explanation involving:

text
set-oriented processing
data transfer
reuse
appropriate database calculation

Part 20 — SQL aggregation vs analytical annotations ​

Answer:

Does this lesson require @Aggregation.default? ​

What is the difference between this grouped CDS query and an analytical model whose measures are aggregated dynamically by an analytical consumer? ​

For this assignment, do not add analytical aggregation annotations.


Part 21 — Deliberate over-grouping experiment ​

Temporarily add:

text
booking_id

to both:

text
select list
GROUP BY

Preview the result.

Answer:

What happened to BookingCount? ​

Why did the aggregate become less useful? ​

Restore the correct model afterward.


Part 22 — Alias experiment ​

Temporarily try to use:

text
CarrierId
CurrencyCode

as if they were the source-field names in the same CDS view's GROUP BY.

Run syntax check.

Then restore:

text
Booking.carrier_id
Booking.currency_code

Record what ADT tells you.


Part 23 — AVG syntax recall ​

Without changing the Booking view, write a valid CDS AVG expression for:

text
Flight.seats_occupied

with result type:

text
abap.dec( 15, 2 )

Compare your answer with the guided ZI_FLIGHT_STATS_### source.

This keeps the AVG syntax in memory without turning amount typing into an unrelated obstacle in the Booking exercise.


Part 24 — DISTINCT reasoning ​

Would this solve the requirement?

text
SELECT DISTINCT carrier_id, currency_code, flight_price

Answer:

Why or why not? ​

Explain the difference between:

text
removing duplicate result rows

and:

text
calculating grouped summaries

Part 25 — Money reasoning ​

Suppose the requirement changes to:

Show one total booking value per carrier, regardless of original currency.

Would simply removing CurrencyCode from GROUP BY be correct?

Explain what extra modeling concern is required.

Hint:

text
currency conversion

Part 26 — SQL Console comparison ​

Write an ABAP SQL query in SQL Console that calculates at least:

text
CarrierId
CurrencyCode
BookingCount
TotalBookingValue

from /DMO/BOOKING.

Compare its result with your CDS Data Preview.

Explain why a reusable CDS entity can still be preferable when the same semantic summary is needed by several consumers.


Part 27 — Architecture explanation ​

Complete:

text
Runner
  ↓
____________________________
  ↓
____________________________
  ↓
GROUP BY + aggregate functions
  ↓
____________________________

Use:

text
Reader
ZI_BOOKING_STATS_###
/DMO/BOOKING

Part 28 — Certification-style requirements task ​

Without looking at the guided source, write the skeleton for a grouped CDS View Entity that has:

text
two dimensions
COUNT(*)
SUM(...)
AVG(... with explicit result type)
GROUP BY
HAVING count(*) >= n

Use placeholder business fields if necessary.

Then compare the skeleton with SAP Help/your lesson.


Part 29 — Reasoning questions ​

1. What is an aggregate expression? ​

2. What does GROUP BY define? ​

3. What is the output grain of your Booking statistics view? ​

4. Why are CarrierId and CurrencyCode grouped? ​

5. Why are TravelId and BookingId not grouped? ​

6. What does COUNT( * ) mean for one group? ​

7. Why does AVG need an explicit result type in CDS? ​

8. What does MIN return? ​

9. Does MAX( FlightPrice ) return the complete booking with the largest price? ​

10. What is the difference between WHERE and HAVING? ​

11. Why can HAVING use an aggregate expression? ​

12. Why should monetary totals preserve currency semantics? ​

13. Does grouping by currency perform conversion? ​

14. What is code pushdown? ​

15. Why should an ABAP consumer not rebuild the same aggregation with a manual loop without a good reason? ​

16. When could a higher CDS layer with WHERE be preferable to direct HAVING? ​


Optional challenge 1 — Layered filtering ​

Create a third CDS View Entity on top of:

text
ZI_BOOKING_STATS_###

Filter:

text
BookingCount >= 2

using:

text
WHERE

Compare this with:

text
ZI_BOOKING_HEAVY_###

which uses HAVING directly.

Explain which view is more reusable and why.


Optional challenge 2 — Aggregate by connection ​

Create another summary with grain:

text
CarrierId + ConnectionId + CurrencyCode

Compare its row count with the carrier/currency summary.

Explain why adding a grouping dimension increases the number of possible groups.


Submission checklist ​


Useful ADT shortcuts ​

ActionShortcut
Open ABAP objectCtrl + Shift + A
Content assistCtrl + Space
Quick FixCtrl + 1
Syntax checkCtrl + F2
ActivateCtrl + F3
Activate inactive objectsCtrl + Shift + F3
CDS Data PreviewF8
Run console classF9
Format sourceShift + F1