Appearance
Lesson 7 Practice — Booking Statistics with Aggregation
The guided lesson summarized:
text
/DMO/FLIGHTNow summarize:
text
/DMO/BOOKINGYour 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
↓
RunnerYou will also create a second grouped CDS View Entity that uses:
text
HAVINGto 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/BOOKINGFind at least:
text
travel_id
booking_id
carrier_id
connection_id
flight_date
flight_price
currency_codeAnswer:
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 + CurrencyCodeWrite 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 USDAnswer:
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 StatisticsUse a modern CDS View Entity.
Do not use obsolete:
text
legacy generated SQL-view-name annotationPart 5 — Required grouping dimensions
Expose:
text
CarrierId
CurrencyCodeUse the source fields:
text
carrier_id
currency_codeBoth dimensions must participate in GROUP BY.
Part 6 — Add BookingCount
Create:
text
BookingCountusing:
text
COUNT(*)Answer:
What exactly does the count represent for one result row?
Part 7 — Add total booking value
Create:
text
TotalBookingValueusing:
text
SUM(flight_price)Preserve the semantic relationship to:
text
CurrencyCodeusing 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_occupiedBefore continuing, write the correct CDS expression from memory for:
text
average occupied seats with two decimal placesThen 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 focusedPart 9 — Add minimum and maximum
Create:
text
LowestBookingValue
HighestBookingValueusing:
text
MIN
MAXPreserve 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
BookingIdbecause 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
F8Inspect several result rows.
For each row, verify mentally:
text
CarrierId
CurrencyCode
BookingCount
TotalBookingValuePart 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 + USDrather 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
TotalBookingValueKeep only groups with at least:
text
2 bookingsUse:
text
HAVINGnot 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 groupsPart 15 — Change the threshold experimentally
Preview with a threshold of:
text
2Then 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:
| Question | WHERE | HAVING |
|---|---|---|
| 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_HEAVYRequirements:
GET_ALLreturns all carrier/currency statistics;GET_HEAVYreturns only the groups kept by theHAVINGview;- use ABAP SQL against the CDS entities;
- sort both results by
CarrierId, thenCurrencyCode; - do not select directly from
/DMO/BOOKINGin the Reader.
Part 18 — Runner
Create:
text
ZCL_CDS_L07_P_###Implement:
text
IF_OO_ADT_CLASSRUNThe Runner should:
- call
GET_ALL; - print a heading and all grouped statistics;
- call
GET_HEAVY; - 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 totalswith:
text
B)
CDS GROUP BY / aggregates
→ ABAP receives summary rowsExplain 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 calculationPart 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_idto both:
text
select list
GROUP BYPreview 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
CurrencyCodeas 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_codeRecord what ADT tells you.
Part 23 — AVG syntax recall
Without changing the Booking view, write a valid CDS AVG expression for:
text
Flight.seats_occupiedwith 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_priceAnswer:
Why or why not?
Explain the difference between:
text
removing duplicate result rowsand:
text
calculating grouped summariesPart 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 conversionPart 26 — SQL Console comparison
Write an ABAP SQL query in SQL Console that calculates at least:
text
CarrierId
CurrencyCode
BookingCount
TotalBookingValuefrom /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/BOOKINGPart 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(*) >= nUse 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 >= 2using:
text
WHERECompare 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 + CurrencyCodeCompare 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
| Action | Shortcut |
|---|---|
| Open ABAP object | Ctrl + Shift + A |
| Content assist | Ctrl + Space |
| Quick Fix | Ctrl + 1 |
| Syntax check | Ctrl + F2 |
| Activate | Ctrl + F3 |
| Activate inactive objects | Ctrl + Shift + F3 |
| CDS Data Preview | F8 |
| Run console class | F9 |
| Format source | Shift + F1 |