CDS Views
Architect / Cross-trackbeginner

CDS Views Part 2: Joins, Expressions, CASE, CAST and Functions

Key takeaway

Build CDS views that do real work in the database: inner and left outer joins, WHERE conditions, CASE expressions, CAST to ABAP types, string and date functions, and session variables such as the system date.

Explanation

📌 KEY POINTS
✅ CDS supports inner join, left outer join, right outer join, cross join and union — far beyond SE11 views.

✅ Calculated fields (CASE, CAST, arithmetic, string and date functions) run in the database, so ABAP receives finished values.

✅ Session variables ($session.system_date, $session.user, $session.system_language, $session.client) give runtime context without parameters.

⚠️ Every calculation needs a stable result type — use CAST to fix length and type, especially in CASE branches that return literals of different lengths.

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Part 1 created a single-table view. Now we combine tables and calculate values in the database.

━━━━━━━━━━━━━━━━━━━━
▶ 1. JOINS

  • inner join: only rows with a match on both sides (order item + its header).
  • left outer join: all rows from the left side, NULL/initial if no match (items with optional text).
  • Give each data source an alias (as item, as head) and prefix fields with it.
  • Join conditions use = on key fields; avoid functions in ON conditions (performance, Part 10).
  • For reusable relations prefer associations (Part 6) over hard joins.

━━━━━━━━━━━━━━━━━━━━
▶ 2. WHERE IN THE VIEW

  • A WHERE clause in the view is a fixed filter for every consumer (e.g. only order type TA).
  • Put only rules that are always true into the view; consumer-specific filters belong in the consumer's SELECT.

━━━━━━━━━━━━━━━━━━━━
▶ 3. CASE

  • Simple CASE: case field when 'A' then … else … end.
  • Searched CASE: case when cond then … end — for ranges and multiple fields.
  • Cast literals to the same type so all branches return one type.

━━━━━━━━━━━━━━━━━━━━
▶ 4. CAST AND ARITHMETIC

  • cast( field as abap.char(10) ), abap.int4, abap.dec(15,2), abap.fltp, or a data element (cast( x as vbeln_va )).
  • Division of integers returns an integer — cast to decimal first, or use division( a, b, dec ).

━━━━━━━━━━━━━━━━━━━━
▶ 5. BUILT-IN FUNCTIONS

  • Strings: concat, concat_with_space, substring, left, right, lpad, replace, upper, lower.
  • Dates: dats_days_between, dats_add_days, dats_add_months, dats_is_valid.
  • Numbers: abs, ceil, floor, round, division, mod.
  • Currency and unit: currency_conversion, unit_conversion (use carefully, Part 10).

━━━━━━━━━━━━━━━━━━━━
▶ 6. SESSION VARIABLES

  • $session.system_date: today's date on the application server.
  • $session.user, $session.system_language, $session.client.
  • Useful for "age of order in days" or language-dependent texts without adding parameters.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. Create ZI_SalesOrderItemEnh: VBAP inner join VBAK.
  2. Add RejectionStatus with a searched CASE on ABGRU and CAST to abap.char(10).
  3. Add SalesArea with concat and AgeInDays with dats_days_between and $session.system_date.
  4. Preview with F8, then read the view from a classic report sorted by AgeInDays.

✅ CHECKPOINT: you can build a joined view with calculated fields that returns finished data to ABAP.

Code example

ABAP Code
// ===== STEP 1: joined view with calculations (ADT DDL source) =====@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Sales order item enriched'define view entity ZI_SalesOrderItemEnh  as select from vbap as item    inner join   vbak as head on head.vbeln = item.vbeln{  key item.vbeln as SalesOrder,  key item.posnr as SalesOrderItem,      item.matnr as Material,      head.kunnr as SoldToParty,      head.erdat as CreationDate,       @Semantics.quantity.unitOfMeasure: 'OrderQuantityUnit'      item.kwmeng as OrderQuantity,      item.vrkme  as OrderQuantityUnit,       @Semantics.amount.currencyCode: 'TransactionCurrency'      item.netwr as NetAmount,      item.waerk as TransactionCurrency, // ===== STEP 2: CASE with cast literals =====      case        when item.abgru = '' then cast( 'OPEN' as abap.char(10) )        else cast( 'REJECTED' as abap.char(10) )      end as RejectionStatus, // ===== STEP 3: string and date functions =====      concat( head.vkorg, head.vtweg ) as SalesArea,      dats_days_between( head.erdat, $session.system_date ) as AgeInDays}where head.auart = 'TA' * ===== STEP 4: classic consumer report =====REPORT zcds_open_item_age. TYPES: BEGIN OF ty_item,         salesorder      TYPE vbeln_va,         salesorderitem  TYPE posnr_va,         material        TYPE matnr,         rejectionstatus TYPE char10,         ageindays       TYPE i,       END OF ty_item. DATA: lt_item TYPE STANDARD TABLE OF ty_item,      ls_item TYPE ty_item. START-OF-SELECTION.  SELECT salesorder salesorderitem material rejectionstatus ageindays    FROM zi_salesorderitemenh    INTO TABLE lt_item    WHERE rejectionstatus = 'OPEN'.   SORT lt_item BY ageindays DESCENDING.   LOOP AT lt_item INTO ls_item.    WRITE: / ls_item-salesorder, ls_item-salesorderitem,             ls_item-material, ls_item-ageindays.  ENDLOOP.

Real project scenario

A backlog report for a pharma client read VBAP and VBAK in nested SELECTs, then calculated order age and status in ABAP loops. For 2 million items it ran 25 minutes.
The team moved the join, the rejection status CASE and the age calculation into one CDS view entity. The report became a single SELECT with a WHERE on RejectionStatus; runtime dropped to under a minute, and the same view fed a Fiori backlog tile.

Common mistakes

  • CASE branches returning literals of different lengths without CAST (type conflict or truncated values).
  • Putting consumer-specific filters (a single sales org) into the view WHERE, making it unusable for others.
  • Using left outer join where inner join is meant, then being surprised by empty fields.
  • Integer division producing 0 instead of a decimal ratio.
  • Using functions on columns in join conditions, blocking index use.

Best practices

  • Alias every data source and prefix every field.
  • CAST calculated fields to explicit types or data elements.
  • Keep fixed business rules in the view, variable filters in the consumer.
  • Use $session variables instead of parameters for today's date or logon language.
  • Prefer associations for optional, reusable relations (Part 6).

Interview angle

Questions: "Which joins does CDS support?", "How do you calculate a field in CDS?", "What are session variables?"
Strong answer: inner, left/right outer, cross join and union; calculated fields with CASE, CAST, arithmetic and built-in string/date/number functions executed in the database; CAST to fix result types; $session.system_date, user, system_language and client provide runtime context. Mention keeping fixed rules in the view and variable filters in the consumer.

Practice this lesson

Quick check

1. A CDS view entity has: case when abgru = '' then 'OPEN' else 'REJECTED' end. What is the cleanest way to guarantee one consistent result type?

2. Which built-in CDS session variable returns the language of the currently logged-on user at runtime?

3. Which CDS SQL expression construct allows conditional value derivation directly within the SELECT list, similar to a multi-branch switch statement?

Interview questions

1. How do you add calculated fields to a CDS view, and what do you watch out for with CASE, CAST and date calculations?

Answer it in your own words first, then compare.

2. A backlog report reads VBAP and VBAK in nested SELECTs and calculates order age and rejection status in ABAP loops. It runs 25 minutes. How would you redesign it with CDS?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics