Skip to content

Lesson 4 Practice — Booking Details with CDS Joins ​

The guided lesson combined:

text
Connection
Carrier
Origin Airport
Destination Airport

into one route model.

In this practice, solve a different relational problem:

A booking stores IDs for a customer and carrier. Build a CDS model that exposes useful booking details together with the related customer and carrier information.

Your architecture will be:

text
/DMO/CUSTOMER ──┐
                 │
/DMO/BOOKING ────┼──→ ZI_BOOKING_DETAIL_###
                 │
/DMO/CARRIER ────┘
                         ↓
                  Booking Reader
                         ↓
                       Runner

The complete solution is intentionally not included here.


Objects to create ​

text
ZI_BOOKING_DETAIL_###
ZCL_BOOKING_READER_###
ZCL_CDS_L04_PRACTICE_###

Replace ### with your own student/group suffix.


Part 1 — Inspect /DMO/BOOKING ​

Open:

text
/DMO/BOOKING

with:

text
Ctrl + Shift + A

Identify:

text
travel_id
booking_id
booking_date
customer_id
carrier_id
connection_id
flight_date
flight_price
currency_code

Confirm that the booking key is:

text
travel_id + booking_id

Open Data Preview.

Record:

text
one Customer ID:
one Carrier ID:

from a booking row.


Part 2 — Inspect /DMO/CUSTOMER ​

Open:

text
/DMO/CUSTOMER

Find:

text
customer_id
first_name
last_name

Find the customer ID you recorded.

Record:

text
First name:
Last name:

Part 3 — Inspect /DMO/CARRIER ​

Open:

text
/DMO/CARRIER

Find:

text
carrier_id
name
currency_code

Find the carrier ID you recorded.

Record:

text
Carrier name:

Part 4 — Design the result model ​

Your CDS entity must expose:

text
TravelId
BookingId
BookingDate

CustomerId
CustomerFirstName
CustomerLastName
CustomerName

CarrierId
CarrierName

ConnectionId
FlightDate
FlightPrice
CurrencyCode

CustomerName should be calculated from:

text
first name + one space + last name

using the CDS expression skills from Lesson 3.


Part 5 — Draw the relationships ​

Complete:

text
Booking.customer_id
        ↓
____________________.____________________

Booking.carrier_id
        ↓
____________________.____________________

Then answer:

Do the target fields identify the corresponding target records? ​


Part 6 — Create the Data Definition ​

Create:

text
ZI_BOOKING_DETAIL_###

Description:

text
Lesson 4 - Booking Detail

Choose a CDS View Entity template.

Use:

text
/DMO/BOOKING

as the primary source with alias:

text
Booking

Part 7 — Join Customer ​

Join:

text
/DMO/CUSTOMER

with alias:

text
Customer

Use:

text
INNER JOIN

The ON condition must match the booking's customer ID to the customer record.

Hint

The shape is:

abap
inner join /dmo/customer as Customer
  on Booking.__________ = Customer.__________

Part 8 — Join Carrier ​

Join:

text
/DMO/CARRIER

with alias:

text
Carrier

Use:

text
INNER JOIN

The ON condition must connect the booking's carrier ID with the carrier key.


Part 9 — Define the CDS keys ​

The CDS entity represents:

text
a booking

Mark as keys only the elements needed to identify a booking.

Do not mark these as keys:

text
CustomerName
CarrierName
FlightPrice

Part 10 — Expose customer information ​

Expose:

text
CustomerId
CustomerFirstName
CustomerLastName

Use qualified source references:

text
Booking.<field>
Customer.<field>

Make the data source of each element obvious.


Part 11 — Calculate CustomerName ​

Use:

text
CONCAT_WITH_SPACE

The result should resemble:

text
Jane Smith

rather than:

text
JaneSmith
Hint

The shape is:

abap
concat_with_space(
  Customer.__________,
  Customer.__________,
  1
) as CustomerName

Part 12 — Expose carrier and booking details ​

Expose:

text
CarrierId
CarrierName
ConnectionId
FlightDate
FlightPrice
CurrencyCode

CarrierName must come from:

text
Carrier

Part 13 — Syntax check and activate ​

Run:

text
Ctrl + F2

Fix all errors.

Activate:

text
Ctrl + F3

Preview:

text
F8

Part 14 — Verify one joined row ​

Choose one booking result.

Compare:

text
CustomerId
CustomerName
CarrierId
CarrierName

with the independent Data Preview results of:

text
/DMO/CUSTOMER
/DMO/CARRIER

Record:

text
Travel ID:
Booking ID:
Customer match verified: Yes / No
Carrier match verified:  Yes / No

Part 15 — Check for row multiplication ​

Inspect whether the same:

text
TravelId + BookingId

appears unexpectedly more than once.

If it does:

  1. inspect the target keys;
  2. inspect the ON conditions;
  3. determine whether one booking is matching several target rows.

Do not immediately add:

text
DISTINCT

Answer:

Why can an incomplete join condition produce several rows for one source record?


Part 16 — SQL Console ​

Query:

text
ZI_BOOKING_DETAIL_###

Return at least:

text
TravelId
BookingId
CustomerName
CarrierId
CarrierName
ConnectionId
FlightDate
FlightPrice
CurrencyCode

Order by:

text
TravelId
BookingId

Part 17 — Filter by carrier ​

Use the carrier ID recorded in Part 1.

Add a SQL Console filter for:

text
CarrierId

Confirm that every result row belongs to that carrier.


Part 18 — Create the Booking Reader ​

Create:

text
ZCL_BOOKING_READER_###

The Reader should not implement:

text
IF_OO_ADT_CLASSRUN

Define:

text
TT_BOOKINGS

as a standard table based directly on:

text
ZI_BOOKING_DETAIL_###

with:

text
WITH EMPTY KEY

Part 19 — Add GET_ALL ​

Create:

text
GET_ALL

Requirements:

  • return TT_BOOKINGS;
  • select from ZI_BOOKING_DETAIL_###;
  • use FIELDS *;
  • order by TravelId, BookingId;
  • contain no direct Customer or Carrier join syntax.

Part 20 — Add GET_BY_CARRIER ​

Create:

text
GET_BY_CARRIER

Import:

text
carrier_id

Return:

text
TT_BOOKINGS

Requirements:

  • select from ZI_BOOKING_DETAIL_###;
  • filter on CDS element CarrierId;
  • use an ABAP SQL host variable;
  • order by TravelId, BookingId.

Part 21 — Create the Runner ​

Create:

text
ZCL_CDS_L04_PRACTICE_###

Implement:

text
IF_OO_ADT_CLASSRUN

In main:

  1. instantiate the Booking Reader;
  2. call GET_ALL;
  3. loop over the result;
  4. display a readable line containing:
text
TravelId/BookingId
CustomerName
CarrierName

Design the exact output yourself.


Part 22 — Test GET_BY_CARRIER ​

Use a carrier ID present in the current tenant.

Call:

text
GET_BY_CARRIER

Display the returned bookings.

Confirm:

text
Reader
  ↓
ZI_BOOKING_DETAIL_###

and not:

text
Reader
  ↓
direct Customer/Carrier joins

Part 23 — Explain INNER JOIN ​

In your own words:

What happens to a booking if its customer_id has no matching /DMO/CUSTOMER row? ​

What happens to a booking if its carrier_id has no matching /DMO/CARRIER row? ​


Part 24 — Think about LEFT OUTER JOIN ​

Without changing your final solution yet, answer:

If the Customer join changed to LEFT OUTER JOIN, what would happen to a booking with no matching Customer row? ​

What would happen to the Customer-side values at SQL level? ​

Would changing only the Customer join change the Carrier join's behavior? ​


Part 25 — Join-type experiment ​

Make a temporary copy or temporary edit.

Change:

text
Customer INNER JOIN

to:

text
Customer LEFT OUTER JOIN

Activate and preview.

Then restore your intended final version.

If the visible result does not change, explain why complete demo reference data can make the two previews look the same even though the join semantics differ.


Part 26 — Reasoning questions ​

Answer in your own words.

1. What problem does a join solve? ​

2. What is the purpose of an ON condition? ​

3. Why should target keys be inspected before writing a join? ​

4. Why are TravelId and BookingId still the keys of the joined model? ​

5. Why is CustomerName not a key? ​

6. Why does CarrierName come from /DMO/CARRIER? ​

7. What is the difference between INNER JOIN and LEFT OUTER JOIN? ​

8. How can one source row become several result rows? ​

9. Why should unexpected duplicates be investigated before using DISTINCT? ​

10. Why is the Reader simpler after the join is modeled in CDS? ​

11. Why are meaningful aliases useful? ​

12. Why will associations be useful after learning joins? ​


Optional challenge 1 — Customer location ​

Expose:

text
CustomerCity
CustomerCountry

from /DMO/CUSTOMER.

Filter the joined CDS entity in SQL Console by a country present in your data.


Optional challenge 2 — Add Connection ​

Join:

text
/DMO/CONNECTION

to the booking model.

Before coding, inspect its key:

text
carrier_id
connection_id

Your ON condition must represent the complete relationship.

Expose:

text
DepartureTime
ArrivalTime

Then answer:

What could happen if you joined only on connection_id and ignored carrier_id?

Hint

A complete relationship needs both booking fields that identify the connection.


Submission checklist ​


Useful ADT shortcuts ​

ActionShortcut
Open ABAP Development ObjectCtrl + Shift + A
Code completionCtrl + Space
Syntax checkCtrl + F2
Activate current objectCtrl + F3
Activate inactive objectsCtrl + Shift + F3
CDS Data PreviewF8
Run console classF9
Format sourceShift + F1