CDS Table Functions Part 2: Building a Table Function with an AMDP Implementation
Build a CDS table function end to end: the CDS definition with parameters and return structure, the AMDP class with FOR TABLE FUNCTION, the SQLScript implementation, activation and a first test in data preview.
Explanation
📌 KEY POINTS
✅ CDS side: define table function … with parameters … returns { … } implemented by method class=>method.
✅ ABAP side: class with if_amdp_marker_hdb and a static method FOR TABLE FUNCTION.
✅ Implementation: BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING <tables>.
⚠️ The SELECT list must match the returns structure exactly — names, order and types.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 1 justified a table function for "age rank per supplier". Now we build ZTF_PurchReqAgingRank.
━━━━━━━━━━━━━━━━━━━━
▶ STEP 1 — THE CDS DEFINITION
- "define table function ZTF_PurchReqAgingRank".
- Parameters: p_keydate (the date for the age calculation).
- "returns { … }": the output structure. For client-dependent data, the first element is the client field (Part 3).
- "implemented by method zcl_tf_purchreq_aging=>get_aging_rank".
Create it in ADT via New → Data Definition → template "Define Table Function with Parameters".
━━━━━━━━━━━━━━━━━━━━
▶ STEP 2 — THE AMDP CLASS
- PUBLIC SECTION: INTERFACES if_amdp_marker_hdb — marks the class as AMDP for HANA.
- CLASS-METHODS get_aging_rank FOR TABLE FUNCTION ztf_purchreqagingrank. — the signature comes from the CDS definition; you do not declare parameters yourself.
━━━━━━━━━━━━━━━━━━━━
▶ STEP 3 — THE SQLSCRIPT IMPLEMENTATION
- METHOD … BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING zpr_head.
- USING lists every database object you read (tables, views, other AMDP functions).
- RETURN SELECT … ; — one result set matching "returns".
- Parameters are available by name (p_keydate); in SQLScript write :p_keydate when used as a variable.
━━━━━━━━━━━━━━━━━━━━
▶ STEP 4 — ACTIVATE AND TEST
- Activate the CDS definition and the class (together if needed).
- Open Data Preview on the table function; enter the parameter.
- Consume it from ABAP SQL: SELECT FROM ztf_purchreqagingrank( p_keydate = @today ) …
━━━━━━━━━━━━━━━━━━━━
▶ STEP 5 — WRAP IT FOR CONSUMERS
Expose the table function through a CDS view entity on top (names, associations, annotations, access control). Consumers then use the view, not the function directly.
💡 TIP: keep the SQLScript as a single declarative SELECT whenever possible; imperative loops and cursors are slow and hard to optimize.
✅ CHECKPOINT: you can create, activate and consume a table function.
Code example
// ===== Step 1: CDS definition =====@EndUserText.label: 'Purchase request age rank per supplier'@ClientHandling.type: #CLIENT_DEPENDENT@ClientHandling.algorithm: #SESSION_VARIABLEdefine table function ZTF_PurchReqAgingRank with parameters @Environment.systemField: #SYSTEM_DATE p_keydate : abap.dats returns { client : abap.clnt; // first element for client-dependent data RequestUUID : sysuuid_x16; RequestID : abap.char(10); Supplier : abap.char(10); DaysOpen : abap.int4; AgeRank : abap.int4; // 1 = oldest open request of the supplier } implemented by method zcl_tf_purchreq_aging=>get_aging_rank; " ===== Step 2+3: AMDP class =====CLASS zcl_tf_purchreq_aging DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. CLASS-METHODS get_aging_rank FOR TABLE FUNCTION ztf_purchreqagingrank.ENDCLASS. CLASS zcl_tf_purchreq_aging IMPLEMENTATION. METHOD get_aging_rank BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING zpr_head. RETURN SELECT client, request_uuid AS "REQUESTUUID", request_id AS "REQUESTID", supplier AS "SUPPLIER", DAYS_BETWEEN( created_on, :p_keydate ) AS "DAYSOPEN", ROW_NUMBER() OVER ( PARTITION BY supplier ORDER BY created_on ) AS "AGERANK" FROM zpr_head WHERE client = SESSION_CONTEXT( 'CDS_CLIENT' ) -- client filter (Part 3) AND status = 'S'; ENDMETHOD.ENDCLASS. " ===== Step 4: consume in ABAP SQL =====" SELECT RequestID, Supplier, DaysOpen" FROM ztf_purchreqagingrank( p_keydate = @( cl_abap_context_info=>get_system_date( ) ) )" WHERE AgeRank <= 3" INTO TABLE @DATA(top3_per_supplier). // ===== Step 5: expose via a view entity for consumers =====// define view entity ZI_PurchReqAgingTop3 with parameters p_keydate : abap.dats// as select from ZTF_PurchReqAgingRank( p_keydate: $parameters.p_keydate )// { key RequestUUID, RequestID, Supplier, DaysOpen, AgeRank }// where AgeRank <= 3Real project scenario
A developer's first table function failed to activate with "result structure does not match". The SQLScript returned request_id before request_uuid and used a DECIMAL for DaysOpen while the CDS returns structure declared INT4.
After aligning the column order, aliases and types exactly with the returns structure, activation worked. The team added a comment block at the top of every table function method listing the returns fields in order, which prevented the same issue in later objects.
Common mistakes
- SELECT list not matching the returns structure (order, names, types).
- Forgetting tables in the USING clause.
- Missing if_amdp_marker_hdb.
- Forgetting the client filter for client-dependent data.
- Imperative loops instead of set-based SQL.
- Consumers reading the function directly instead of a wrapping view.
Best practices
- Start from the ADT template.
- Mirror the returns structure exactly in the RETURN SELECT.
- Keep SQLScript declarative and short.
- Handle client explicitly.
- Wrap the function in a view entity for consumers.
Interview angle
Questions: "How do you create a CDS table function?", "What does FOR TABLE FUNCTION mean?", "What must match between CDS and SQLScript?"
Strong answer: CDS "define table function" with parameters, returns structure and "implemented by method"; an AMDP class with if_amdp_marker_hdb and a static method FOR TABLE FUNCTION (signature derived from CDS); implementation BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING …, returning a SELECT whose columns match the returns structure; handle client; wrap in a view entity.
Practice this lesson
Quick check
1. When defining the AMDP method that implements a CDS table function, what must be consistent between the CDS DDL signature and the AMDP method signature?
2. Which ABAP artifact must be implemented to provide the executable logic behind a CDS table function?
3. What happens if the result set structure produced by the AMDP method does not match the RETURNS structure declared for the CDS table function?
Interview questions
1. A table function fails to activate with "result structure does not match". What do you check?
Answer it in your own words first, then compare.
2. What is a CDS table function and how is it built?
Answer it in your own words first, then compare.
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.