CDS patterns that compress code
What you'll learn
Aggregation, associations and group by turn loops-and-COLLECT into a few declarative lines — but the group by must list every non-aggregated field.
- Aggregation (count/sum/max/min/avg), associations, and group by compress the most code.
- Associations are declared joins, navigated by name and materialized only when used.
- Every non-aggregated select field must appear in the group by.
A surprising amount of classic ABAP — nested loops, COLLECT statements, manual subtotalling — collapses into a few lines of CDS. The three patterns that compress the most code are aggregation (count, sum, max, min, avg), associations (declared joins you navigate by name), and group by. Written as a `define view entity ... as select from ...`, the view is pushed to HANA and consumable everywhere.
Aggregation replaces hand-rolled totalling: `count(*)`, `sum(h.total)`, `max(h.orderdate)` are computed on the database in a single scan. Associations replace repeated explicit joins: you declare `association [0..*] to zorder_item as _items on ...` once and expose or navigate it by name, and the join is materialized only when the association is actually used. Together they turn a screen of procedural code into a declarative contract.
The rule that commonly trips up newcomers: when a view aggregates, the `group by` must list *every* non-aggregated field in the select list. Miss one and the view often activates but errors at runtime — the activator catches many cases, but not when an expression appears in the select. Treat it as a discipline: every plain field in the projection appears verbatim in the group by.
Key points
- Aggregation (count/sum/max/min/avg), associations, and group by compress the most code.
- Associations are declared joins, navigated by name and materialized only when used.
- Every non-aggregated select field must appear in the group by.
- A missing group-by field may activate but error at runtime — expressions slip past the activator.
- Use `define view entity` (CDS view entity), not the legacy DDIC-based `define view`.
Examples
Classic: select all rows, then loop and collect per customer — rows travel to the app server just to be counted.
ABAPselect customerid, total, orderdate
from zorder_hdr
where status = 'OPEN'
into table @data(lt_hdr).
loop at lt_hdr assigning field-symbol(<h>).
ls_sum-customerid = <h>-customerid.
ls_sum-ordercount = 1.
ls_sum-totalopen = <h>-total.
collect ls_sum into lt_sum.
endloop.Aggregation, an association and a group by covering every non-aggregated field; pushed to HANA, consumable from Open SQL, RAP, analytics and OData.
ABAP@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Open Orders By Customer'
define view entity ZI_OpenOrdersByCustomer
as select from zorder_hdr as h
association [0..*] to zorder_item as _items
on _items.OrderId = h.OrderId
{
key h.CustomerId,
count(*) as OrderCount,
sum(h.Total) as TotalOpenAmount,
max(h.OrderDate) as LastOrderDate,
_items
}
where h.Status = 'OPEN'
group by h.CustomerIdSource notes: clean-core-curriculum §6.2
Ask Claude
Build a prompt from this lesson + your question and open a fresh Claude chat with it pre-filled — handy for adapting a before/after pattern to your own object.