
Sap Abap Cds
- 539 installs
- 399 repo stars
- Updated August 4, 2026
- secondsky/sap-skills
sap-abap-cds is a secondsky SAP skill that helps developers author and refine ABAP Core Data Services views and entities for ERP data models in S/4HANA landscapes.
About
sap-abap-cds is a skill in secondsky/sap-skills for SAP practitioners building Core Data Services artifacts on ABAP stacks. It guides authoring and refining CDS views and entities that model ERP data and expose analytical and transactional interfaces within S/4HANA environments. SAP developers and integration engineers reach for sap-abap-cds when OData or Fiori consumers need stable, semantically rich data definitions instead of ad-hoc SQL copies. The skill fits enterprise backend work where CDS annotations, associations, and entity projections must align with standard SAP data models.
- SAP ABAP CDS modeling guidance
- Enterprise ERP data view authoring
- Supports S/4HANA analytical exposures
- Reduces CDS syntax and annotation mistakes
Sap Abap Cds by the numbers
- 539 all-time installs (skills.sh)
- +46 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #778 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/secondsky/sap-skills --skill sap-abap-cdsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 539 |
|---|---|
| repo stars | ★ 399 |
| Last updated | August 4, 2026 |
| Repository | secondsky/sap-skills ↗ |
How do you create ABAP CDS views in S/4HANA?
Author and refine SAP ABAP Core Data Services views and entities for ERP data models, exposing analytical and transactional interfaces in S/4HANA landscapes.
Who is it for?
SAP ABAP developers modeling ERP data in S/4HANA who need CDS views and entities for analytical or transactional APIs.
Skip if: Non-SAP web stacks, generic SQL database design, or teams without ABAP or S/4HANA landscape access.
When should I use this skill?
The user asks to create, refine, or expose ABAP CDS views, entities, or ERP data models in S/4HANA.
What you get
ABAP CDS view definitions, entity models, associations, annotations, and exposure-ready data interfaces for SAP landscapes.
- CDS view definitions
- Entity models
- Association and annotation specs
Files
SAP ABAP CDS (Core Data Services)
Related Skills
- sap-abap: Use for ABAP programming patterns used with CDS or when implementing EML statements in ABAP
- sap-btp-cloud-platform: Use for CDS deployment scenarios on BTP or ABAP Environment configurations
- sap-fiori-tools: Use when building Fiori Elements applications that consume CDS views or working with UI annotations
- sap-cap-capire: Use for comparing CDS syntax between ABAP and CAP or when integrating ABAP CDS with CAP services
- sap-api-style: Use when documenting CDS-based OData services or following API documentation standards
When to Use This Skill
Use this skill when creating ABAP CDS views or view entities, defining associations and cardinalities, adding UI or semantic annotations, implementing DCL access control, handling currency/unit fields, troubleshooting CDS compiler errors, or comparing classic CDS views with newer view entities.
Quick Reference: https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds.html | SAP Cheat Sheets: https://github.com/SAP-samples/abap-cheat-sheets/blob/main/15_CDS_View_Entities.md
Version Compatibility
This skill covers CDS features from 7.40 SP8 through ABAP Cloud. Key version boundaries:
| Feature | 7.40 SP8 | 7.50 | 7.51 | 7.55+ |
|---|---|---|---|---|
CDS View (DEFINE VIEW) | x | x | x | x |
| CDS associations, parameters, built-in functions | x | x | x | x |
CDS Table Functions (DEFINE TABLE FUNCTION) | x | x | x | |
| CDS Access Control (DEFINE ROLE / pfcg_auth) | x | x | x | x |
| CDS Access Control (implicit evaluation) | x | x | x | |
Session variables ($session.user/client/system_language) | x | x | x | x |
@Environment.systemField annotation | x | x | x | |
UPPER/LOWER functions | x | x | ||
$session.system_date | x | x | ||
CDS Metadata Extensions (ANNOTATE VIEW) | x | x | ||
| Cross Join in CDS | x | x | ||
| CDS View Entity (`DEFINE VIEW ENTITY`) | x | |||
New cardinality syntax (to one/to many) | 7.57+ |
On a 7.40 system: Use DEFINE VIEW (not DEFINE VIEW ENTITY). CDS table functions are not available before 7.50. Basic DCL (DEFINE ROLE with pfcg_auth) is available from 7.40 SP08, but implicit role evaluation in ABAP SQL requires 7.50+. $session.user/client/system_language are available from 7.40 SP08. The templates in templates/ include both classic CDS View and View Entity variants.
Table of Contents
- 1. CDS View Fundamentals
- 2. Essential Annotations
- 3. Expressions and Operations
- 4. Built-in Functions
- 5. Joins
- 6. Associations
- 7. Input Parameters
- 8. Aggregate Expressions
- 9. Access Control (DCL)
- 10. Data Retrieval from ABAP
- 11. Common Errors and Solutions
- 12. Useful Transactions and Tables
- Bundled Resources
- Source Documentation
---
1. CDS View Fundamentals
View Types
| Type | Syntax | Database View | Since |
|---|---|---|---|
| CDS View | DEFINE VIEW | Yes | 7.4 SP8 |
| CDS View Entity | DEFINE VIEW ENTITY | No | 7.55 |
Recommendation: Use CDS View Entities for new development.
Basic CDS View Syntax
@AbapCatalog.sqlViewName: 'ZCDS_EXAMPLE_V'
@AbapCatalog.compiler.CompareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Example CDS View'
define view ZCDS_EXAMPLE
as select from db_table as t
{
key t.field1,
t.field2,
t.field3 as AliasName
}CDS View Entity Syntax (7.55+)
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Example View Entity'
define view entity Z_CDS_EXAMPLE
as select from db_table as t
{
key t.field1,
t.field2,
t.field3 as AliasName
}Key Difference: View entities omit @AbapCatalog.sqlViewName - no SQL view generated.
Eclipse ADT Setup
1. File → New → Other → Core Data Services → Data Definition 2. Enter name, description, and package 3. Select template (view, view entity, etc.)
---
2. Essential Annotations
Core Annotations
Essential annotations for CDS development:
@AbapCatalog.sqlViewName- SQL view name (max 16 chars)@AbapCatalog.compiler.CompareFilter- Optimize WHERE clauses@AccessControl.authorizationCheck- Set to #NOT_REQUIRED, #CHECK, #MANDATORY, or #NOT_ALLOWED@EndUserText.label- User-facing description@Metadata.allowExtensions- Allow view extensions
Complete Reference: See references/annotations-reference.md for 50+ annotations with examples.
Semantics Annotations (Currency/Quantity)
Required for CURR and QUAN data types to avoid error SD_CDS_ENTITY105:
-- Currency fields
@Semantics.currencyCode: true
waers,
@Semantics.amount.currencyCode: 'waers'
amount,
-- Quantity fields
@Semantics.unitOfMeasure: true
meins,
@Semantics.quantity.unitOfMeasure: 'meins'
quantityUI Annotations (Fiori Elements)
@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
field1,
@UI.hidden: true
internal_fieldConsumption Annotations (Value Help)
@Consumption.valueHelpDefinition: [{
entity: { name: 'I_Currency', element: 'Currency' }
}]
waersFor complete annotation reference, see references/annotations-reference.md.
---
3. Expressions and Operations
CASE Expressions
Simple CASE (single variable comparison):
case status
when 'A' then 'Active'
when 'I' then 'Inactive'
else 'Unknown'
end as StatusTextSearched CASE (multiple conditions):
case
when amount > 1000 then 'High'
when amount > 100 then 'Medium'
else 'Low'
end as AmountCategoryComparison Operators
Standard operators: =, <>, <, >, <=, >= Special operators: BETWEEN x AND y, LIKE, IS NULL, IS NOT NULL
Complete Reference: See references/expressions-reference.md for all operators and expressions.
Arithmetic Operations
quantity * price as TotalAmount,
amount / 100 as Percentage,
-amount as NegatedAmountSession Variables
Available system variables (SY fields equivalent):
$session.user(SY-UNAME) - Current user [7.40 SP08+]$session.client(SY-MANDT) - Client [7.40 SP08+]$session.system_language(SY-LANGU) - Language [7.40 SP08+]$session.system_date(SY-DATUM) - Current date [7.51+]
Note: $session.user/client/system_language are available from 7.40 SP08.$session.system_daterequires 7.51+.@Environment.systemFieldrequires 7.50+.
Complete Reference: See references/expressions-reference.md for all system variables.
$session.user as CurrentUser,
$session.system_date as Today---
4. Built-in Functions
CDS provides comprehensive built-in functions for string, numeric, and date operations.
Key Function Categories
- String Functions: concat(), length(), substring(), upper(), lower(), replace()
- Numeric Functions: abs(), ceil(), floor(), round(), division()
- Date Functions: dats_add_days(), dats_add_months(), dats_days_between()
- CAST Expression: Convert between ABAP data types
Note:upper()andlower()in CDS require 7.51+. On 7.40/7.50, case
conversion must be performed in ABAP after selecting (there is no CDS equivalent).
Complete Reference: See references/functions-reference.md for all 50+ functions with examples.
Quick Examples
-- String operations
concat(first_name, last_name) as FullName,
upper(name) as UpperName,
substring(description, 1, 10) as ShortDesc
-- Numeric operations
abs(amount) as AbsoluteAmount,
round(value, 2) as RoundedValue,
division(10, 3, 2) as PreciseDivision
-- Date operations
dats_add_days(current_date, 7) as NextWeek,
dats_days_between(start_date, end_date) as Duration
-- Type conversion
cast(field as abap.char(10)) as TextField,
cast(amount as abap.curr(15,2)) as CurrencyField
**ABAP Types**: `abap.char()`, `abap.numc()`, `abap.int4`, `abap.dats`, `abap.tims`, `abap.curr()`, `abap.cuky`, `abap.quan()`, `abap.unit()`
---
## 5. Joins
### Join Types-- INNER JOIN (matching rows only) inner join makt as t on m.matnr = t.matnr
-- LEFT OUTER JOIN (all from left, matching from right) left outer join marc as c on m.matnr = c.matnr
-- RIGHT OUTER JOIN (all from right, matching from left) -- [7.51+] right outer join mvke as v on m.matnr = v.matnr
-- CROSS JOIN (cartesian product) -- [7.51+] cross join t001 as co
---
## 6. Associations
Associations define relationships between entities (join-on-demand):
### Defining Associations
define view Z_ASSOC_EXAMPLE as select from scarr as c association [1..*] to spfli as _Flights on $projection.carrid = _Flights.carrid association [0..1] to sairport as _Airport on $projection.hub = _Airport.id { key c.carrid, c.carrname, c.hub,
// Expose associations _Flights, _Airport }
### Cardinality Notation
**Syntax mapping**:
- `[0..1]` or `[1]` → `association to one` (LEFT OUTER MANY TO ONE)
- `[1..1]` → `association to one` (exact match)
- `[0..*]` or `[*]` → `association to many` (LEFT OUTER MANY TO MANY)
- `[1..*]` → `association to many` (one or more)
**Complete Reference**: See `references/associations-reference.md` for detailed cardinality guide.
### New Cardinality Syntax (Release 2302+)
association to one _Customer on ... -- [0..1] association to many _Items on ... -- [0..*]
### Using Associations
-- Expose for consumer use _Customer,
-- Ad-hoc field access (triggers join) _Customer.name as CustomerName
### Path Expressions with Filter
-- Filter with cardinality indicator _Items[1: Status = 'A'].ItemNo
For complete association reference, see `references/associations-reference.md`.
---
## 7. Input Parameters
### Defining Parameters
define view Z_PARAM_EXAMPLE with parameters p_date_from : dats, p_date_to : dats, @Environment.systemField: #SYSTEM_LANGUAGE p_langu : spras as select from vbak as v { key v.vbeln, v.erdat, v.erzet } where v.erdat between :p_date_from and :p_date_to
### Parameter Reference
Use colon notation `:p_date_from` or `$parameters.p_date_from`
**Calling from ABAP**:SELECT * FROM z_param_example( p_date_from = '20240101', p_date_to = '20241231', p_langu = @sy-langu ) INTO TABLE @DATA(lt_result).
---
## 8. Aggregate Expressions
### Aggregate Functions
define view Z_AGG_EXAMPLE as select from vbap as i { i.vbeln, sum(i.netwr) as TotalAmount, avg(i.netwr) as AvgAmount, max(i.netwr) as MaxAmount, min(i.netwr) as MinAmount, count(*) as ItemCount } group by i.vbeln having sum(i.netwr) > 1000
---
## 9. Access Control (DCL)
### Basic DCL Structure
@MappingRole: true define role Z_CDS_EXAMPLE_DCL { grant select on Z_CDS_EXAMPLE where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03'); }
### Authorization Check Options
**Available values**:
- `#NOT_REQUIRED` - No authorization check
- `#CHECK` - Warning if no DCL exists
- `#MANDATORY` - Error if no DCL exists
- `#NOT_ALLOWED` - DCL ignored if exists
**Complete Reference**: See `references/access-control-reference.md` for detailed DCL patterns.
### Condition Types
**PFCG Authorization**: `where (field) = aspect pfcg_auth(AUTH_OBJECT, AUTH_FIELD, ACTVT = '03')`
**Literal Condition**: `where status <> 'DELETED'`
**User Aspect**: `where created_by ?= aspect user`
**Combined**: `where (bukrs) = aspect pfcg_auth(...) and status = 'ACTIVE'`
For complete access control reference, see `references/access-control-reference.md`.
---
## 10. Data Retrieval from ABAP
### Standard SELECTSELECT * FROM zcds_example WHERE field1 = @lv_value INTO TABLE @DATA(lt_result).
### SALV IDA (Integrated Data Access)cl_salv_gui_table_ida=>create_for_cds_view( CONV #( 'ZCDS_EXAMPLE' ) )->fullscreen( )->display( ).
---
## 11. Common Errors and Solutions
### SD_CDS_ENTITY105: Missing Reference Information
**Problem**: CURR/QUAN fields without reference
**Solution**: Add semantics annotations@Semantics.currencyCode: true waers, @Semantics.amount.currencyCode: 'waers' netwr
Or import currency from related table:inner join t001 as c on ... { c.waers, @Semantics.amount.currencyCode: 'waers' v.amount }
### Cardinality Warnings
**Problem**: Cardinality doesn't match actual data
**Solution**: Define cardinality matching data modelassociation [0..1] to ... -- Use for optional relationships association [1..*] to ... -- Use for required one-to-many
For complete troubleshooting guide, see `references/troubleshooting.md`.
---
## 12. Useful Transactions and Tables
### Key Transactions
- **SDDLAR** - Display/repair DDL structures
- **RSRTS_ODP_DIS** - TransientProvider preview
- **RSRTS_QUERY_CHECK** - CDS query metadata validation
- **SE63** - Translation (EndUserText)
- **SE11** - ABAP Dictionary
- **SU21** - Authorization objects
### Important Tables
- **DDHEADANNO** - Header-level annotations
- **CDSVIEWANNOPOS** - CDS view header annotations
- **CDS_FIELD_ANNOTATION** - Field-level annotations
- **ABDOC_CDS_ANNOS** - SAP annotation definitions
### API Class
`CL_DD_DDL_ANNOTATION_SERVICE` - Programmatic annotation access:
- `get_annos()` - Get all annotations
- `get_label_4_element()` - Get @EndUserText.label
---
## Bundled Resources
### Reference Documentation
For detailed guidance, see the reference files in `references/`:
- `annotations-reference.md` - Complete annotation catalog
- `functions-reference.md` - All built-in functions with examples
- `associations-reference.md` - Associations and cardinality guide
- `access-control-reference.md` - DCL and authorization patterns
- `expressions-reference.md` - Expressions and operators
- `troubleshooting.md` - Common errors and solutions
### Templates
For templates, see `templates/`:
- `basic-view.md` - Standard CDS view template
- `parameterized-view.md` - View with input parameters
- `dcl-template.md` - Access control definition
---
## Source Documentation
**Update this skill by checking**:
- https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds.html (ABAP Cloud)
- https://help.sap.com/doc/abapdocu_740_index_htm/7.40/en-US/index.htm (7.40 Reference)
- https://help.sap.com/docs/SAP_NETWEAVER_AS_ABAP_752/f2e545608079437ab165c105649b89db/7c078765ec6d4e6b88b71bdaf8a2bd9f.html (NetWeaver 7.52 User Guide)
- https://github.com/SAP-samples/abap-cheat-sheets
- https://github.com/SAP-samples/abap-cheat-sheets/blob/main/33_ABAP_Release_News.md (Release News)
**Last Verified**: 2026-04-02
SAP ABAP CDS (Core Data Services) Skill
Comprehensive Claude Code skill for SAP ABAP CDS view development, annotations, expressions, and access control.
Capability Index
| Capability | Status |
|---|---|
| Commands | 1: /abap-cds-model-check |
| Agents | 0 |
| Hooks | No |
| MCP | No |
| LSP | No |
| Source Freshness | last_verified: 2026-04-02; CDS activation and ATC behavior still require system verification. |
| Verification | npm run validate; production ABAP system checks pending unless explicitly documented. |
Overview
This skill provides complete reference material for developing CDS views in SAP ABAP, from basic view creation to advanced topics like associations, access control, and performance optimization.
When to Use This Skill
Use this skill when:
- Creating CDS views or view entities in ABAP
- Defining data models with annotations
- Working with associations and cardinality
- Implementing input parameters
- Using built-in functions (string, numeric, date/time)
- Writing CASE expressions and conditional logic
- Implementing access control with DCL
- Handling CURR/QUAN data types
- Troubleshooting CDS errors (SD_CDS_ENTITY105)
- Querying CDS views from ABAP
- Displaying data with SALV IDA
Keywords
Core CDS Terms
- ABAP CDS
- Core Data Services
- CDS view
- CDS view entity
- define view
- define view entity
- DDL (Data Definition Language)
- DCL (Data Control Language)
Annotations
- @AbapCatalog
- @AbapCatalog.sqlViewName
- @AbapCatalog.compiler.CompareFilter
- @AccessControl
- @AccessControl.authorizationCheck
- @EndUserText
- @EndUserText.label
- @EndUserText.quickInfo
- @Semantics
- @Semantics.currencyCode
- @Semantics.amount
- @Semantics.unitOfMeasure
- @Semantics.quantity
- @UI
- @UI.lineItem
- @UI.identification
- @UI.selectionField
- @UI.hidden
- @UI.facet
- @UI.fieldGroup
- @UI.dataPoint
- @Consumption
- @Consumption.valueHelpDefinition
- @ObjectModel
- @ObjectModel.text
- @Metadata
- @Metadata.allowExtensions
- @Metadata.ignorePropagatedAnnotations
- @Analytics
- @Search
Associations
- association
- cardinality
- TO ONE
- TO MANY
- path expressions
- exposed association
- join-on-demand
- $projection
Parameters
- input parameters
- WITH PARAMETERS
- $parameters
- @Environment.systemField
Functions
- built-in functions
- string functions
- concat
- substring
- upper
- lower
- length
- replace
- lpad
- rpad
- ltrim
- rtrim
- numeric functions
- abs
- ceil
- floor
- round
- div
- division
- mod
- date functions
- dats_add_days
- dats_add_months
- dats_days_between
- dats_is_valid
- coalesce
- CAST
- aggregate functions
- SUM
- AVG
- MIN
- MAX
- COUNT
Expressions
- CASE expression
- simple CASE
- searched CASE
- arithmetic operations
- comparison operators
- BETWEEN
- LIKE
- IS NULL
- session variables
- $session
- $session.user
- $session.system_language
- $session.system_date
Joins
- INNER JOIN
- LEFT OUTER JOIN
- RIGHT OUTER JOIN
- CROSS JOIN
Access Control
- DEFINE ROLE
- DCL
- pfcg_auth
- authorization
- MappingRole
- aspect user
- access control
Data Types
- CURR
- QUAN
- currencyCode
- unitOfMeasure
- abap.dats
- abap.tims
- abap.char
- abap.numc
- abap.int4
- abap.curr
- abap.cuky
- abap.quan
- abap.unit
Tools and Transactions
- Eclipse ADT
- ABAP Development Tools
- SDDLAR
- SALV IDA
- cl_salv_gui_table_ida
- cl_salv_table
- CL_DD_DDL_ANNOTATION_SERVICE
Errors
- SD_CDS_ENTITY105
- missing reference information
- cardinality mismatch
Related Technologies
- Fiori Elements
- OData
- RAP
- ABAP RESTful Application Programming Model
- ABAP Cloud
- S/4HANA
- BTP ABAP Environment
Skill Structure
sap-abap-cds/
├── SKILL.md # Main skill file
├── README.md # This file
├── references/
│ ├── annotations-reference.md # Complete annotation catalog
│ ├── functions-reference.md # All built-in functions
│ ├── associations-reference.md # Associations and cardinality
│ ├── access-control-reference.md # DCL and authorization
│ ├── expressions-reference.md # Expressions and operators
│ └── troubleshooting.md # Common errors and solutions
└── templates/
├── basic-view.md # Standard CDS view template
├── parameterized-view.md # View with parameters template
└── dcl-template.md # Access control templateQuick Examples
Basic CDS View
@AbapCatalog.sqlViewName: 'ZEXAMPLE_V'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Example View'
define view Z_EXAMPLE as select from db_table
{
key field1,
field2
}CDS View Entity (7.55+)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Example View Entity'
define view entity Z_EXAMPLE_E as select from db_table
{
key field1,
field2
}Association
association [0..1] to target as _Target
on $projection.key_field = _Target.key_fieldAccess Control
@MappingRole: true
define role Z_EXAMPLE_DCL {
grant select on Z_EXAMPLE
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03');
}Documentation Sources
- SAP Help Portal (ABAP Cloud): https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds.html
- SAP NetWeaver 7.52 CDS User Guide: https://help.sap.com/docs/SAP_NETWEAVER_AS_ABAP_752/f2e545608079437ab165c105649b89db/7c078765ec6d4e6b88b71bdaf8a2bd9f.html
- SAP ABAP Cheat Sheets: https://github.com/SAP-samples/abap-cheat-sheets
- SAP Community: https://community.sap.com/t5/tag/CDS%20Views/tg-p
- Codezentrale: https://codezentrale.de/category/sap/sap-abap/sap-abap-cdsviews/
Requirements
- SAP NetWeaver 7.4 SP8+ for CDS Views
- SAP NetWeaver 7.55+ for CDS View Entities
- Eclipse with ABAP Development Tools (ADT)
- SAP HANA database (recommended)
Version
- Skill Version: 1.0.0
- Last Verified: 2026-04-02
- ABAP Release: 7.4 SP8+ / ABAP Cloud
License
GPL-3.0 License
ABAP CDS Access Control Reference
Complete reference for implementing access control in ABAP CDS using DCL (Data Control Language).
Source: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_authorizations.htm
Version Note: CDS access control with implicit role evaluation in ABAP SQL requires
7.50+. Basic DCL (DEFINE ROLEwithpfcg_auth) is available from 7.40 SP08.
Full access rules, inherited access rules, and user conditions require 7.51+.
On 7.40, DCL roles are defined but not automatically enforced in ABAP SQL.
---
Overview
CDS Access Control provides row-level security for CDS views. Access rules are defined in DCL (Data Control Language) source files that map to CDS views and restrict data based on:
- PFCG authorization objects
- Literal conditions
- User identity
- Combination of conditions
---
Creating Access Control in ADT
1. File → New → Other → Core Data Services → Access Control 2. Enter:
- Name: Same as CDS view or custom name
- Description
- Protected Entity: The CDS view to protect
3. Select template
---
Basic DCL Structure
@EndUserText.label: 'Access Control for Z_CDS_VIEW'
@MappingRole: true
define role Z_CDS_VIEW_DCL {
grant select on Z_CDS_VIEW
where condition;
}Key Elements
| Element | Purpose |
|---|---|
@MappingRole: true | Required - maps role to all users |
define role | Creates the access control object |
grant select on | Specifies the protected CDS view |
where | Defines the access condition |
---
Authorization Check Annotation
Control whether DCL is required:
@AccessControl.authorizationCheck: #CHECK
define view Z_CDS_VIEW as select from ...| Value | Behavior |
|---|---|
#NOT_REQUIRED | No DCL needed, full access granted |
#CHECK | Warning if no DCL exists |
#MANDATORY | Syntax error if no DCL exists |
#NOT_ALLOWED | Any existing DCL is ignored |
---
Condition Types
1. PFCG Authorization Condition
Map CDS fields to PFCG authorization objects:
@MappingRole: true
define role Z_SALES_DCL {
grant select on Z_SALES_ORDER
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03');
}Syntax:
where (cds_field) = aspect pfcg_auth(AUTH_OBJECT, AUTH_FIELD, ACTVT = 'value')Components:
cds_field: Field from the CDS viewAUTH_OBJECT: Authorization object (from SU21)AUTH_FIELD: Authorization field within the objectACTVT: Activity (usually '03' for display)
2. Multiple Authorization Fields
where (vkorg, vtweg, spart) =
aspect pfcg_auth(V_VBAK_VKO, VKORG, VTWEG, SPART, ACTVT = '03');Fields are mapped positionally to authorization fields.
3. Multiple Authorization Objects
@MappingRole: true
define role Z_COMPLEX_DCL {
grant select on Z_CDS_VIEW
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03')
and (vkorg, vtweg, spart) =
aspect pfcg_auth(V_VBAK_VKO, VKORG, VTWEG, SPART, ACTVT = '03');
}4. Literal Condition
Compare field to fixed value:
@MappingRole: true
define role Z_ACTIVE_ONLY_DCL {
grant select on Z_CDS_VIEW
where status = 'ACTIVE';
}Operators:
=Equal<>Not equal<,>,<=,>=Comparisonbetween ... and ...RangelikePattern matching
5. User Aspect
Restrict to current user:
@MappingRole: true
define role Z_USER_DCL {
grant select on Z_USER_DATA
where created_by ?= aspect user;
}Note: ?= allows NULL values to match.
6. Environment Aspect
Access environment values:
where client = aspect environment.client---
Operator Variants
Standard Operator (=)
where (bukrs) = aspect pfcg_auth(...)Only authorized values returned.
Optional Operator (?=)
where (bukrs) ?= aspect pfcg_auth(...)NULL and initial values also allowed.
---
Combining Conditions
AND Combination
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03')
and status = 'ACTIVE'
and created_by ?= aspect user;OR Combination
where status = 'PUBLIC'
or created_by ?= aspect user;Complex Logic
where (
(bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03')
and status = 'ACTIVE'
)
or status = 'PUBLIC';---
Inheritance and Propagation
No Automatic Inheritance
Access control does NOT automatically apply when:
- CDS view is used as data source in another view
- View is accessed via association
Each view needs its own DCL for protection.
Recommended Pattern
Create DCL for all views in a hierarchy:
-- Base view DCL
define role Z_BASE_DCL {
grant select on Z_BASE_VIEW
where (bukrs) = aspect pfcg_auth(...);
}
-- Consumer view DCL
define role Z_CONSUMER_DCL {
grant select on Z_CONSUMER_VIEW
where (bukrs) = aspect pfcg_auth(...);
}---
Common Authorization Objects
Finance
| Object | Fields | Description |
|---|---|---|
| F_BKPF_BUK | BUKRS, ACTVT | Company code |
| F_BKPF_GSB | GSBER, ACTVT | Business area |
| F_BKPF_KOA | KOART, ACTVT | Account type |
Sales
| Object | Fields | Description |
|---|---|---|
| V_VBAK_VKO | VKORG, VTWEG, SPART, ACTVT | Sales org/channel/division |
| V_VBAK_AAT | AUART, ACTVT | Order type |
Materials
| Object | Fields | Description |
|---|---|---|
| M_MATE_WRK | WERKS, ACTVT | Plant |
| M_MATE_MAR | MTART, ACTVT | Material type |
Controlling
| Object | Fields | Description |
|---|---|---|
| K_CCA | KOKRS, KOSTL, ACTVT | Cost center |
| K_ORDER | AUFNR, ACTVT | Internal order |
Find objects: Transaction SU21 (Authorization Objects)
---
Activity Values (ACTVT)
| Value | Activity |
|---|---|
| 01 | Create |
| 02 | Change |
| 03 | Display |
| 06 | Delete |
| 16 | Execute |
Most CDS views use ACTVT = '03' (display).
---
Examples
Company Code Authorization
@MappingRole: true
define role Z_COMPANY_DCL {
grant select on Z_FINANCIAL_DATA
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03');
}Sales Organization + Status Filter
@MappingRole: true
define role Z_SALES_DCL {
grant select on Z_SALES_ORDER
where (vkorg, vtweg, spart) =
aspect pfcg_auth(V_VBAK_VKO, VKORG, VTWEG, SPART, ACTVT = '03')
and status <> 'DELETED';
}Own Records Only
@MappingRole: true
define role Z_OWN_DATA_DCL {
grant select on Z_USER_TASKS
where assigned_to ?= aspect user;
}Public + Owned Records
@MappingRole: true
define role Z_MIXED_DCL {
grant select on Z_DOCUMENTS
where visibility = 'PUBLIC'
or created_by ?= aspect user;
}Multi-level Authorization
@MappingRole: true
define role Z_MULTILEVEL_DCL {
grant select on Z_MATERIAL_DATA
where (werks) = aspect pfcg_auth(M_MATE_WRK, WERKS, ACTVT = '03')
and (mtart) = aspect pfcg_auth(M_MATE_MAR, MTART, ACTVT = '03');
}---
Testing Access Control
In ADT
1. Right-click CDS view → Open With → Data Preview 2. Data shown reflects current user's authorizations
Via ABAP
" Access control automatically applied
SELECT * FROM z_secured_view
INTO TABLE @DATA(lt_data).
" Bypass access control (if allowed)
SELECT * FROM z_secured_view
BYPASSING BUFFER
INTO TABLE @DATA(lt_all_data).Note: BYPASSING BUFFER does NOT bypass DCL.
Checking User Authorizations
AUTHORITY-CHECK OBJECT 'F_BKPF_BUK'
ID 'BUKRS' FIELD '1000'
ID 'ACTVT' FIELD '03'.
IF sy-subrc = 0.
" User has authorization
ENDIF.---
Best Practices
1. Always add DCL for sensitive data: Don't rely on application-level checks alone 2. Use #CHECK or #MANDATORY: Avoid accidental exposure 3. Match cardinality: Ensure DCL doesn't create unexpected duplicates 4. Test with multiple users: Verify different authorization profiles 5. Document authorization requirements: Comment the DCL source 6. Use ?= for optional fields: Handle NULL values gracefully
---
Troubleshooting
No Data Returned
1. Check user's PFCG role assignments 2. Verify authorization object values in SU21 3. Test authorization with AUTHORITY-CHECK 4. Check DCL condition logic
Syntax Errors
1. Verify CDS view exists 2. Check field names match exactly 3. Verify authorization object/field names
Performance Issues
1. Ensure proper indexes on authorization fields 2. Consider restructuring complex OR conditions 3. Test with representative data volumes
---
Documentation Links
- SAP Help - Access Control (ABAP Platform): https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_access_control.htm
- SAP Community - DCL Guide: https://blogs.sap.com/2017/09/09/all-about-data-control-language-dcls/
- SAP GitHub - Authorization Checks: https://github.com/SAP-samples/abap-cheat-sheets/blob/main/25_Authorization_Checks.md
Last Updated: 2025-11-23
ABAP CDS Annotations Reference
Complete reference for ABAP CDS annotations organized by category.
Source: https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds_annotations.html
---
Annotation Syntax
@AnnotationName: value
@AnnotationName.property: value
@AnnotationName: [{ property1: value1, property2: value2 }]Annotations can be placed at:
- Header level: Before
define view - Element level: Before field in projection list
- Parameter level: Before parameter definition
---
1. AbapCatalog Annotations
Control ABAP Dictionary integration:
| Annotation | Purpose | Values | Required |
|---|---|---|---|
@AbapCatalog.sqlViewName | SQL view name (max 16 chars) | String | Yes (CDS View) |
@AbapCatalog.compiler.CompareFilter | Optimize WHERE clause | true/false | No |
@AbapCatalog.preserveKey | Preserve key structure | true/false | No |
@AbapCatalog.buffering.status | Buffering mode | #ACTIVE, #SWITCHED_OFF | No |
@AbapCatalog.buffering.type | Buffer type | #SINGLE, #GENERIC, #FULL | No |
Example:
@AbapCatalog.sqlViewName: 'ZV_EXAMPLE'
@AbapCatalog.compiler.CompareFilter: true
@AbapCatalog.preserveKey: true
define view Z_EXAMPLE as select from ...---
2. AccessControl Annotations
Define authorization behavior:
| Annotation | Purpose | Values |
|---|---|---|
@AccessControl.authorizationCheck | Authorization requirement | #NOT_REQUIRED, #CHECK, #MANDATORY, #NOT_ALLOWED |
@AccessControl.personalData.blocking | Data blocking | #REQUIRED, #NOT_REQUIRED |
Values Explained:
#NOT_REQUIRED: No DCL needed, full access granted#CHECK: Warning in Eclipse if DCL missing#MANDATORY: Syntax error if DCL missing#NOT_ALLOWED: DCL ignored even if exists
Example:
@AccessControl.authorizationCheck: #CHECK
define view Z_SECURED_VIEW as select from ...---
3. EndUserText Annotations
Provide user-facing labels and descriptions:
| Annotation | Purpose | Level |
|---|---|---|
@EndUserText.label | Display label | Header, Element |
@EndUserText.quickInfo | Tooltip/hover text | Header, Element |
Example:
@EndUserText.label: 'Sales Order Header'
define view Z_SALES_ORDER as select from vbak
{
@EndUserText.label: 'Order Number'
@EndUserText.quickInfo: 'Unique sales document identifier'
vbeln
}Translation: Use transaction SE63 to translate these texts.
---
4. Metadata Annotations
Control metadata behavior and extensions:
| Annotation | Purpose | Values |
|---|---|---|
@Metadata.allowExtensions | Allow metadata extensions | true/false |
@Metadata.ignorePropagatedAnnotations | Block annotation inheritance | true/false |
Example:
@Metadata.allowExtensions: true
@Metadata.ignorePropagatedAnnotations: true
define view Z_EXTENSIBLE_VIEW as select from ...---
5. Semantics Annotations
Communicate field semantic meaning to frameworks:
Currency and Amount
| Annotation | Purpose | Example |
|---|---|---|
@Semantics.currencyCode: true | Mark as currency code field | waers |
@Semantics.amount.currencyCode: 'field' | Reference currency for amount | netwr |
@Semantics.currencyCode: true
waers,
@Semantics.amount.currencyCode: 'waers'
netwrQuantity and Unit
| Annotation | Purpose | Example |
|---|---|---|
@Semantics.unitOfMeasure: true | Mark as UoM field | meins |
@Semantics.quantity.unitOfMeasure: 'field' | Reference UoM for quantity | menge |
@Semantics.unitOfMeasure: true
meins,
@Semantics.quantity.unitOfMeasure: 'meins'
mengeAdministrative Fields
| Annotation | Purpose |
|---|---|
@Semantics.user.createdBy: true | Created by user |
@Semantics.user.lastChangedBy: true | Last changed by user |
@Semantics.systemDateTime.createdAt: true | Creation timestamp |
@Semantics.systemDateTime.lastChangedAt: true | Last change timestamp |
@Semantics.systemDateTime.localInstanceLastChangedAt: true | Local instance timestamp |
@Semantics.user.createdBy: true
ernam,
@Semantics.systemDateTime.createdAt: true
erdatOther Semantics
| Annotation | Purpose |
|---|---|
@Semantics.booleanIndicator: true | Character field as boolean |
@Semantics.language: true | Language key field |
@Semantics.text: true | Text/description field |
---
6. UI Annotations
Control Fiori Elements rendering:
List Report Annotations
| Annotation | Purpose | Properties |
|---|---|---|
@UI.lineItem | Table column | position, importance, label |
@UI.selectionField | Filter field | position |
@UI.hidden | Hide element | true/false |
@UI.lineItem: [{ position: 10, importance: #HIGH }]
@UI.selectionField: [{ position: 10 }]
vbeln,
@UI.hidden: true
internal_idObject Page Annotations
| Annotation | Purpose | Properties |
|---|---|---|
@UI.identification | Object page field | position, label |
@UI.fieldGroup | Field group member | position, qualifier |
@UI.facet | Page section | purpose, type, label, targetQualifier |
@UI.headerInfo | Header configuration | typeName, typeNamePlural, title, description |
@UI.facet: [{
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
label: 'General Information',
targetQualifier: 'GeneralInfo'
}]
@UI.fieldGroup: [{ qualifier: 'GeneralInfo', position: 10 }]
vbeln,
@UI.fieldGroup: [{ qualifier: 'GeneralInfo', position: 20 }]
erdatStatus and Data Points
| Annotation | Purpose |
|---|---|
@UI.dataPoint | KPI/Status display |
@UI.textArrangement | Text display order |
@UI.dataPoint: { qualifier: 'Status', title: 'Order Status' }
@UI.textArrangement: #TEXT_ONLY
statusText Arrangement Values: #TEXT_FIRST, #TEXT_LAST, #TEXT_ONLY, #TEXT_SEPARATE
---
7. Consumption Annotations
Control consumer framework behavior:
Value Help
@Consumption.valueHelpDefinition: [{
entity: {
name: 'I_Currency',
element: 'Currency'
},
additionalBinding: [{
localElement: 'CompanyCode',
element: 'CompanyCode',
usage: #FILTER_AND_RESULT
}]
}]
waersFilter
@Consumption.filter: {
selectionType: #RANGE,
multipleSelections: true,
mandatory: true
}
bukrsDerived Type
@Consumption.derivedType.defaultFilter: 'I_SALESORDER'---
8. ObjectModel Annotations
Define data model characteristics:
Text Association
@ObjectModel.text.element: ['StatusText']
status,
@Semantics.text: true
StatusTextForeign Key
@ObjectModel.foreignKey.association: '_Customer'
kunnr,
_CustomerComposition
@ObjectModel.composition: true
_ItemsTransactional Processing
@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.writeActivePersistence: 'DB_TABLE'---
9. Analytics Annotations
For analytical applications and embedded analytics:
| Annotation | Purpose |
|---|---|
@Analytics.dataCategory | Data category |
@Analytics.dataExtraction.enabled | Enable extraction |
@DefaultAggregation | Default aggregation |
@Analytics.dataCategory: #FACT
define view Z_ANALYTICS_FACT as select from ...
{
@DefaultAggregation: #SUM
amount
}---
10. Search Annotations
Enable search functionality:
| Annotation | Purpose |
|---|---|
@Search.searchable: true | Enable search on view |
@Search.defaultSearchElement: true | Include in default search |
@Search.fuzzinessThreshold | Fuzzy search threshold (0-1) |
@Search.ranking | Search result ranking |
@Search.searchable: true
define view Z_SEARCHABLE as select from ...
{
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
@Search.ranking: #HIGH
name
}---
11. Environment Annotations
Inject system values into parameters:
| Annotation | System Field |
|---|---|
@Environment.systemField: #SYSTEM_DATE | SY-DATUM |
@Environment.systemField: #SYSTEM_TIME | SY-UZEIT |
@Environment.systemField: #SYSTEM_LANGUAGE | SY-LANGU |
@Environment.systemField: #USER | SY-UNAME |
@Environment.systemField: #CLIENT | SY-MANDT |
define view Z_WITH_DEFAULTS
with parameters
@Environment.systemField: #SYSTEM_DATE
p_date : abap.dats,
@Environment.systemField: #SYSTEM_LANGUAGE
p_lang : spras
as select from ...---
Finding Annotations in Eclipse/ADT
1. Open Development Object: Ctrl+Shift+A 2. Filter by type: DDLA (annotation definition) 3. Browse annotations: View all available definitions
API Access
DATA: lo_service TYPE REF TO cl_dd_ddl_annotation_service.
cl_dd_ddl_annotation_service=>create(
EXPORTING iv_cds_view = 'Z_CDS_VIEW'
RECEIVING ro_service = lo_service
).
" Get all annotations
DATA(lt_annos) = lo_service->get_annos( ).
" Get specific label
DATA(lv_label) = lo_service->get_label_4_element(
iv_element = 'FIELD_NAME'
iv_language = sy-langu
).
" Display the retrieved label
WRITE: / 'Field Label:', lv_label.---
System Tables
| Table | Content |
|---|---|
| DDHEADANNO | Header-level annotations |
| CDSVIEWANNOPOS | CDS view header annotations |
| CDS_FIELD_ANNOTATION | Field-level annotations |
| ABDOC_CDS_ANNOS | SAP annotation definitions |
| DDDDLSRCT | DDL source texts |
---
Best Practices
1. Always set authorization check: Use @AccessControl.authorizationCheck 2. Add labels: Use @EndUserText.label for user-facing views 3. Document currencies/quantities: Required for CURR/QUAN fields 4. Use consistent positioning: Number position values by 10s for easy insertion 5. Leverage text associations: Use @ObjectModel.text.element for code-text pairs
---
Documentation Links
- SAP Help - Annotations (Cloud): https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds_annotations.html
- SAP Help - Annotations (7.50): https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abencds_annotations_sap.htm
- UI Annotations Reference: https://ui5.sap.com/#/api/sap.ui.comp.smartfield.SmartField
Last Updated: 2025-11-23
ABAP CDS Associations Reference
Complete reference for defining and using associations in ABAP CDS views.
Source: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abencds_f1_association.htm
Version Note: Associations with explicit join type (INNER,LEFT OUTER) are available
from 7.40 SP08. New cardinality syntax (association to one/to many) requires
7.57+ / S/4HANA Cloud Release 2302+. On 7.40, use bracket notation[0..1],[1..*].
---
What Are Associations?
Associations define relationships between CDS entities. Unlike joins, associations are join-on-demand - the actual database join only occurs when fields from the associated entity are accessed.
Key Benefits:
- Lazy evaluation improves performance
- Cleaner data model representation
- Reusable relationship definitions
- Support for navigation in OData and RAP
---
Association Syntax
Basic Definition
define view Z_EXAMPLE as select from source_table as s
association [cardinality] to target_entity as _Alias
on condition
{
key s.key_field,
s.field1,
// Expose association
_Alias
}Naming Convention
SAP recommends prefixing association aliases with underscore:
_Customer_Items_Currency
This distinguishes associations from regular fields.
---
Cardinality
Cardinality Notation
| Syntax | Meaning | Join Type |
|---|---|---|
[0..1] | Zero or one | LEFT OUTER MANY TO ONE |
[1] | Exactly one (shorthand for [0..1]) | LEFT OUTER MANY TO ONE |
[1..1] | Exactly one | LEFT OUTER MANY TO ONE |
[0..*] | Zero or more | LEFT OUTER MANY TO MANY |
[*] | Zero or more (shorthand) | LEFT OUTER MANY TO MANY |
[1..*] | One or more | LEFT OUTER MANY TO MANY |
| No cardinality | Default [0..1] | LEFT OUTER MANY TO ONE |
New Cardinality Syntax (Release 2302+)
association to one _Target on ... -- Equivalent to [0..1]
association to many _Targets on ... -- Equivalent to [0..*]Compatibility Note: This simplified syntax is available in SAP S/4HANA Cloud 2302+ and SAP NetWeaver ABAP 7.57+. Earlier releases require the bracketed cardinality notation [0..1], [0..*], etc.
Cardinality Examples
-- Optional single record (e.g., customer details)
association [0..1] to customer_details as _Details
on $projection.kunnr = _Details.kunnr
-- Required single record (e.g., company code)
association [1..1] to t001 as _Company
on $projection.bukrs = _Company.bukrs
-- Multiple records (e.g., order items)
association [0..*] to order_items as _Items
on $projection.vbeln = _Items.vbeln
-- At least one record expected
association [1..*] to spfli as _Flights
on $projection.carrid = _Flights.carrid---
Join Condition
Using $projection
Reference fields from the current view's projection:
association [0..1] to makt as _Text
on $projection.matnr = _Text.matnr
and $projection.spras = _Text.sprasUsing Source Alias
Reference fields from the source table directly:
define view Z_EXAMPLE as select from mara as m
association [0..1] to makt as _Text
on m.matnr = _Text.matnrComplex Conditions
association [0..*] to price_conditions as _Prices
on $projection.matnr = _Prices.matnr
and $projection.vkorg = _Prices.vkorg
and _Prices.valid_from <= $session.system_date
and _Prices.valid_to >= $session.system_date---
Exposing Associations
Direct Exposure
Makes association available to consumers:
{
key field1,
field2,
// Expose entire association
_Customer,
_Items
}Redirected Association
Redirect to a different target:
_Customer : redirected to Z_CUSTOMER_VIEWFiltered Association
Expose with additional filter:
_Items[Status = 'ACTIVE'] as _ActiveItems---
Using Associations
Ad-hoc Field Access
Access individual fields (triggers join):
{
key vbeln,
_Customer.name1 as CustomerName,
_Customer.ort01 as CustomerCity
}Path Expressions
Navigate through associations:
_Header._Customer.name1 as CustomerNamePath Filter with Cardinality Indicator
When filtering reduces a to-many association to single record:
_Items[1: ItemNumber = '000010'].Material as FirstItemMaterialThe 1: indicates the filter results in a single record.
---
Association vs Join Comparison
When to Use Associations
| Use Associations When | Use Joins When |
|---|---|
| Relationship is optional | All fields always needed |
| Navigation from consumers | Complex join conditions |
| OData/RAP integration | Performance-critical aggregations |
| Clean data model | Multiple conditions on same table |
Performance Difference
Association (Join-on-Demand):
define view Z_WITH_ASSOC as select from vbak
association [0..1] to kna1 as _Customer
on $projection.kunnr = _Customer.kunnr
{
key vbeln,
kunnr,
_Customer -- Join NOT executed yet
}
-- ABAP: SELECT vbeln, kunnr FROM z_with_assoc
-- Only 2 fields selected, no join neededJoin (Always Executed):
define view Z_WITH_JOIN as select from vbak as v
left outer join kna1 as c on v.kunnr = c.kunnr
{
key v.vbeln,
v.kunnr,
c.name1 -- Join ALWAYS executed
}
-- ABAP: SELECT vbeln, kunnr FROM z_with_join
-- Join executed even if name1 not needed---
Default Association
Create association to same entity type for self-reference:
define view Z_HIERARCHY as select from org_unit as o
association [0..1] to Z_HIERARCHY as _Parent
on $projection.parent_id = _Parent.org_unit_id
{
key org_unit_id,
parent_id,
name,
_Parent
}---
Propagated Associations
Associations from underlying views are automatically propagated:
-- Base view
define view Z_BASE as select from mara
association [0..1] to makt as _Text on ...
{
key matnr,
_Text
}
-- Consuming view - _Text is automatically available
define view Z_CONSUMER as select from Z_BASE
{
key matnr,
_Text -- Propagated from Z_BASE
}Blocking Propagation
@Metadata.ignorePropagatedAnnotations: true
define view Z_NO_PROPAGATION as select from Z_BASE
{
key matnr
// _Text NOT available unless explicitly defined
}---
Composition Associations
For parent-child relationships in RAP:
define view entity Z_SALES_ORDER
as select from vbak
composition [0..*] of Z_SALES_ORDER_ITEM as _Items
{
key vbeln,
erdat,
_Items
}
define view entity Z_SALES_ORDER_ITEM
as select from vbap
association to parent Z_SALES_ORDER as _Header
on $projection.vbeln = _Header.vbeln
{
key vbeln,
key posnr,
matnr,
_Header
}---
Accessing Associations in ABAP
Using Path Expression
SELECT
vbeln,
\_Customer-name1 AS customer_name,
\_Customer-ort01 AS customer_city
FROM z_sales_order
INTO TABLE @DATA(lt_result).Using Exposed Association
SELECT FROM z_sales_order
FIELDS vbeln,
\_Customer[ ]-name1 AS customer_name
INTO TABLE @DATA(lt_result).---
Performance Optimization
TO ONE Optimization
SAP HANA optimizes TO ONE cardinality:
- Join can be pruned if target fields not selected
- Better query plan generation
-- Good: Enables optimization
association [0..1] to kna1 as _Customer on ...
-- Avoid if actually single record:
association [0..*] to kna1 as _Customer on ...Cardinality Warnings
Set correct cardinality to avoid: 1. Syntax warnings in ADT 2. Unexpected duplicate rows 3. Performance issues
---
Common Patterns
Master Data Text Association
association [0..1] to makt as _Text
on $projection.matnr = _Text.matnr
and _Text.spras = $session.system_language
{
key matnr,
_Text.maktx as MaterialDescription
}Currency/Unit Association
association [0..1] to tcurc as _Currency
on $projection.waers = _Currency.waers
{
waers,
@Semantics.amount.currencyCode: 'waers'
netwr,
_Currency
}Hierarchical Data
association [0..1] to Z_CATEGORY as _Parent
on $projection.parent_id = _Parent.category_id
association [0..*] to Z_CATEGORY as _Children
on $projection.category_id = _Children.parent_id---
Restrictions
1. No to-many in WHERE for extend view: Cannot filter on [n..] associations in view extensions 2. Cardinality must match data: Mismatched cardinality causes warnings/errors 3. No aggregate on associations: Cannot use SUM/AVG directly on associated fields 4. Path depth limits*: Very deep paths may impact performance
---
Documentation Links
- SAP Help - Associations: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abencds_f1_association.htm
- SAP Community - Cardinality: https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/cardinality-of-association-in-cds-view/ba-p/13351899
- New Cardinality Syntax: https://community.sap.com/t5/application-development-and-automation-blog-posts/new-cardinality-syntax-for-performance-optimization-in-abap-cds-and-abap/ba-p/13554546
Last Updated: 2025-11-23
ABAP CDS Expressions Reference
Complete reference for expressions, operators, and conditional logic in ABAP CDS views.
Source: https://discoveringabap.com/2021/10/13/exploring-abap-on-hana-7-expressions-operations-in-cds-views/
Version Note:$session.user,$session.client,$session.system_languagerequire 7.40 SP08.
$session.system_date requires 7.51+. CASE, arithmetic, and CAST expressionsare available from 7.40 SP08.
---
Projection List Elements
The projection list (SELECT list) can contain:
| Element | Description | Alias Required |
|---|---|---|
| Field | Table/view field | Optional |
| Literal | Constant value | Yes |
| Expression | Calculated value | Yes |
| Session Variable | System value | Yes |
| Association | Relationship | Optional |
---
Field References
Simple Field
{
matnr,
maktx
}With Source Prefix
{
source.matnr,
source.maktx
}With Alias
{
matnr as MaterialNumber,
maktx as Description
}Key Fields
{
key matnr,
key spras,
maktx
}---
Literals
Typed Literals
{
'EUR' as DefaultCurrency, -- Character
100 as DefaultQuantity, -- Integer
123.45 as DefaultPrice, -- Decimal
abap.dats'20241115' as FixedDate -- Typed date
}Untyped Literals
{
'Active' as StatusText,
0 as InitialValue
}Note: Literals require an alias.
---
Session Variables
Access ABAP system fields:
| Variable | Equivalent | Since |
|---|---|---|
$session.user | SY-UNAME | 7.4 SP8 |
$session.client | SY-MANDT | 7.4 SP8 |
$session.system_language | SY-LANGU | 7.4 SP8 |
$session.system_date | SY-DATUM | 7.51 |
{
$session.user as CurrentUser,
$session.client as ClientId,
$session.system_language as Language,
$session.system_date as Today
}---
Comparison Operators
Basic Operators
| Operator | Description | Example |
|---|---|---|
= | Equal | status = 'A' |
<> | Not equal | status <> 'D' |
< | Less than | amount < 1000 |
> | Greater than | amount > 0 |
<= | Less or equal | date <= $session.system_date |
>= | Greater or equal | priority >= 1 |
BETWEEN Operator
where date between '20240101' and '20241231'
-- Equivalent to:
where date >= '20240101' and date <= '20241231'IN Operator
where status in ('A', 'B', 'C')
-- Equivalent to:
where status = 'A' or status = 'B' or status = 'C'NULL Checks
where description is null
where description is not nullPattern Matching (LIKE)
where name like 'SAP%' -- Starts with SAP
where name like '%GmbH' -- Ends with GmbH
where name like '%Partner%' -- Contains Partner
where code like 'A_B' -- A followed by any char, then BEscape Character:
where name like '%10#%%' escape '#' -- Contains literal %---
Arithmetic Operations
Basic Arithmetic
| Operation | Operator | Example |
|---|---|---|
| Addition | + | price + tax |
| Subtraction | - | gross - discount |
| Multiplication | * | quantity * price |
| Division | / | total / count |
| Negation | - | -amount |
Examples
{
quantity * unit_price as LineTotal,
gross_amount - discount as NetAmount,
total / 100 as Percentage,
-balance as NegatedBalance
}Operator Precedence
1. () Parentheses 2. - Negation 3. *, / Multiplication, Division 4. +, - Addition, Subtraction
-- Without parentheses: 10 + (5 * 2) = 20
10 + 5 * 2
-- With parentheses: (10 + 5) * 2 = 30
(10 + 5) * 2---
CASE Expressions
Simple CASE
Compare single expression to multiple values:
case status
when 'A' then 'Active'
when 'I' then 'Inactive'
when 'D' then 'Deleted'
else 'Unknown'
end as StatusTextSearched CASE
Multiple independent conditions:
case
when amount > 10000 then 'High'
when amount > 1000 then 'Medium'
when amount > 0 then 'Low'
else 'Zero'
end as AmountCategoryNested CASE
case type
when 'S' then
case status
when 'A' then 'Sales Active'
when 'C' then 'Sales Closed'
else 'Sales Other'
end
when 'P' then 'Purchase'
else 'Other'
end as TypeDescriptionCASE with Calculations
case indicator
when 'H' then amount
when 'S' then -amount
else 0
end as SignedAmountCASE in WHERE Clause
where case
when type = 'A' then priority
else 0
end > 5Note: Using CASE in WHERE clause is useful for conditional filtering without creating intermediate computed fields. However, it may impact query performance compared to post-filtering in ABAP or using separate WHERE conditions. Use judiciously on large datasets.
---
Logical Operators
AND
Both conditions must be true:
where status = 'A' and type = 'S'OR
At least one condition must be true:
where status = 'A' or status = 'B'NOT
Negates condition:
where not status = 'D'
-- Equivalent to: where status <> 'D'Complex Logic
where (status = 'A' and type = 'S')
or (status = 'B' and priority > 5)Precedence
1. NOT 2. AND 3. OR
Use parentheses for clarity:
-- Unclear:
where a = 1 or b = 2 and c = 3
-- Clear:
where a = 1 or (b = 2 and c = 3)---
Aggregate Expressions
Functions
| Function | Description |
|---|---|
sum(field) | Sum of values |
avg(field) | Average |
min(field) | Minimum |
max(field) | Maximum |
count(*) | Row count |
count(distinct field) | Distinct count |
GROUP BY
Required for non-aggregated fields:
{
customer,
sum(amount) as TotalAmount,
count(*) as OrderCount
}
group by customerHAVING
Filter aggregated results:
{
customer,
sum(amount) as TotalAmount
}
group by customer
having sum(amount) > 10000Complete Example
define view Z_CUSTOMER_SUMMARY as select from sales_order
{
customer,
sum(amount) as TotalSales,
avg(amount) as AvgOrderValue,
min(order_date) as FirstOrder,
max(order_date) as LastOrder,
count(*) as OrderCount,
count(distinct product) as UniqueProducts
}
group by customer
having count(*) >= 5---
Path Expressions
Navigate through associations:
Basic Path
_Customer.name1 as CustomerNameMulti-level Path
_Order._Customer._Country.name as CountryNamePath with Filter
_Items[ItemNumber = '000010'].Material as FirstMaterialCardinality Indicator
When filter reduces to single result:
_Items[1: Status = 'A'].Quantity as ActiveQty---
Conditional Navigation
Combine CASE with paths:
case
when type = 'C' then _Customer.name1
when type = 'V' then _Vendor.name1
else 'Unknown'
end as PartnerName---
NULL Handling
COALESCE
Return first non-null value:
coalesce(override_price, standard_price, 0) as EffectivePriceCASE with NULL
case
when field is null then 'Not Set'
else field
end as SafeFieldArithmetic with NULL
NULL in arithmetic produces NULL:
-- If discount is NULL, result is NULL
price - discount as NetPrice
-- Safe version:
price - coalesce(discount, 0) as NetPrice---
Type Conversion
Implicit Conversion
Some conversions happen automatically.
Explicit CAST
cast(numeric_field as abap.char(10)) as TextField,
cast(char_field as abap.int4) as IntField,
cast(amount as abap.curr(15,2)) as FormattedAmountCommon Type Conversions
| From | To | Example |
|---|---|---|
| NUMC | CHAR | cast(numc as abap.char(n)) |
| INT | CHAR | cast(int as abap.char(n)) |
| CHAR | INT | cast(char as abap.int4) |
| CURR | DEC | cast(curr as abap.dec(n,d)) |
---
Best Practices
1. Use parentheses: Clarify complex logic 2. Handle NULL: Use COALESCE or CASE 3. Alias expressions: Always name calculated fields 4. Type consistency: Ensure CASE branches return same type 5. Performance: Simple expressions perform better
---
Documentation Links
- ABAP Keyword Documentation — CDS DDL: CDS View Entity, sql_functions: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_f1_builtin_functions.htm
- Discovering ABAP - Expressions: https://discoveringabap.com/2021/10/13/exploring-abap-on-hana-7-expressions-operations-in-cds-views/
Last Updated: 2025-11-23
ABAP CDS Built-in Functions Reference
Complete reference for all built-in functions available in ABAP CDS views.
Source: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_f1_builtin_functions.htm
Version Note:concat(),substring(),replace(),length()are available from
7.40 SP08.upper()andlower()require 7.51+. Date/time conversion functions
(tstmp_to_dats,dats_tims_to_tstmp, etc.) require 7.51+. Currency/unit conversion
functions are available from 7.40 SP08. Numeric functions (abs,ceil,floor,
round,division) are available from 7.40 SP08.
---
String Functions
concat(arg1, arg2)
Concatenates two strings.
concat(first_name, last_name) as FullName
-- 'John' + 'Doe' = 'JohnDoe'concat_with_space(arg1, arg2, spaces)
Concatenates strings with specified number of spaces.
concat_with_space(first_name, last_name, 1) as FullName
-- 'John' + 'Doe' = 'John Doe'length(string)
Returns the length of a string.
length(description) as DescLength
-- 'Hello' = 5left(string, n)
Returns leftmost n characters.
left(material_number, 4) as MaterialPrefix
-- '12345678' = '1234'right(string, n)
Returns rightmost n characters.
right(material_number, 3) as MaterialSuffix
-- '12345678' = '678'substring(string, pos, len)
Extracts substring from position for length.
substring(document_number, 3, 5) as SubDoc
-- '1234567890' starting at 3 for 5 = '34567'Note: Position is 1-based.
upper(string)
Converts to uppercase.
upper(name) as NameUpper
-- 'Hello World' = 'HELLO WORLD'lower(string)
Converts to lowercase.
lower(name) as NameLower
-- 'Hello World' = 'hello world'lpad(string, length, pad_char)
Left-pads string to specified length.
lpad(document_number, 10, '0') as PaddedDoc
-- '12345' = '0000012345'Note: If original length exceeds target, string is truncated.
rpad(string, length, pad_char)
Right-pads string to specified length.
rpad(name, 20, ' ') as PaddedName
-- 'John' = 'John 'ltrim(string, trim_char)
Removes characters from left side.
ltrim(document_number, '0') as TrimmedDoc
-- '0000012345' = '12345'rtrim(string, trim_char)
Removes characters from right side.
rtrim(name, ' ') as TrimmedName
-- 'John ' = 'John'replace(string, old, new)
Replaces all occurrences of substring.
replace(phone, '-', '') as PhoneClean
-- '123-456-7890' = '1234567890'instr(string, substring)
Finds position of substring (0 if not found).
instr(email, '@') as AtPosition
-- 'user@example.com' = 5---
Numeric Functions
abs(number)
Returns absolute value.
abs(amount) as AbsoluteAmount
-- -100 = 100
-- 100 = 100ceil(number)
Rounds up to nearest integer.
ceil(price) as CeilingPrice
-- 5.1 = 6
-- 5.9 = 6
-- -5.1 = -5floor(number)
Rounds down to nearest integer.
floor(price) as FloorPrice
-- 5.1 = 5
-- 5.9 = 5
-- -5.1 = -6round(number, decimals)
Rounds to specified decimal places.
round(price, 2) as RoundedPrice
-- 5.567 with 2 decimals = 5.57
-- 5.564 with 2 decimals = 5.56Negative decimals: Round to left of decimal point
round(12345, -2) as RoundedThousands
-- 12345 = 12300div(dividend, divisor)
Integer division (truncates decimal).
div(total_minutes, 60) as Hours
-- 125 / 60 = 2division(dividend, divisor, decimals)
Division with specified decimal precision.
division(10, 3, 4) as Result
-- 10 / 3 with 4 decimals = 3.3333mod(dividend, divisor)
Returns remainder (modulo).
mod(total_minutes, 60) as RemainingMinutes
-- 125 mod 60 = 5---
Date and Time Functions
dats_add_days(date, days)
Adds days to date.
dats_add_days(order_date, 7) as DeliveryDate
-- '20241115' + 7 = '20241122'Negative days: Subtract days
dats_add_days(order_date, -30) as PreviousMonthdats_add_months(date, months)
Adds months to date.
dats_add_months(start_date, 1) as NextMonth
-- '20241115' + 1 = '20241215'dats_days_between(date1, date2)
Returns days between two dates.
dats_days_between(order_date, delivery_date) as LeadTime
-- '20241101' to '20241115' = 14Note: Returns negative if date1 > date2.
dats_is_valid(date)
Validates date (returns 1 or 0).
dats_is_valid(input_date) as IsValidDate
-- '20241115' = 1
-- '00000000' = 0
-- '20241332' = 0---
Timestamp Functions
tstmp_add_seconds(timestamp, seconds, fail)
Adds seconds to timestamp.
tstmp_add_seconds(created_at, 3600, 'FAIL') as OneHourLatertstmp_seconds_between(ts1, ts2, fail)
Seconds between timestamps.
tstmp_seconds_between(start_ts, end_ts, 'FAIL') as DurationSecondststmp_current_utctimestamp()
Current UTC timestamp.
tstmp_current_utctimestamp() as CurrentTimestampNote: The third parameter in timestamp functions controls error handling. Use 'FAIL' to propagate errors if timestamps are invalid, or 'NULL' to return NULL on error. Ensure timestamps are in valid format (YYYYMMDDHHMMSS) before using these functions.
---
COALESCE Function
coalesce(arg1, arg2, ...)
Returns first non-null argument.
coalesce(customer_name, 'Unknown') as DisplayName
-- NULL = 'Unknown'
-- 'John' = 'John'
coalesce(override_price, standard_price, 0) as FinalPrice
-- First non-null value---
CAST Expression
Syntax
cast(expression as data_type)ABAP Data Types
| Type | Syntax | Example |
|---|---|---|
| Character | abap.char(n) | cast(num as abap.char(10)) |
| Numeric text | abap.numc(n) | cast(num as abap.numc(8)) |
| Integer | abap.int4 | cast(str as abap.int4) |
| Date | abap.dats | cast(str as abap.dats) |
| Time | abap.tims | cast(str as abap.tims) |
| Currency key | abap.cuky | cast('EUR' as abap.cuky) |
| Currency amount | abap.curr(n,d) | cast(num as abap.curr(15,2)) |
| Unit of measure | abap.unit(n) | cast('KG' as abap.unit(3)) |
| Quantity | abap.quan(n,d) | cast(num as abap.quan(13,3)) |
| Decimal | abap.dec(n,d) | cast(num as abap.dec(11,2)) |
| String | abap.string | cast(char as abap.string) |
| Raw | abap.raw(n) | cast(hex as abap.raw(16)) |
Examples
-- Convert number to text with leading zeros
lpad(cast(document_number as abap.char(10)), 10, '0') as FormattedDoc,
-- Fixed currency literal
cast('EUR' as abap.cuky) as DefaultCurrency,
-- Decimal precision
cast(amount as abap.curr(15,2)) as FormattedAmountPRESERVING TYPE
Maintain original type definition:
cast(field as abap.char(10) preserving type) as TypedField---
Aggregate Functions
Used with GROUP BY clause.
sum(field)
Sum of values.
sum(amount) as TotalAmountavg(field)
Average of values.
avg(price) as AveragePricemin(field)
Minimum value.
min(order_date) as FirstOrdermax(field)
Maximum value.
max(order_date) as LastOrdercount(*)
Count rows.
count(*) as RowCountcount(distinct field)
Count distinct values.
count(distinct customer) as UniqueCustomersExample with GROUP BY
define view Z_ORDER_SUMMARY as select from vbap
{
vbeln,
sum(netwr) as TotalAmount,
count(*) as ItemCount,
min(erdat) as FirstItemDate,
max(erdat) as LastItemDate,
avg(netwr) as AverageAmount
}
group by vbeln
having sum(netwr) > 1000---
Special Functions
decimal_shift(amount, currency)
Shifts decimal based on currency decimals.
decimal_shift(amount => netwr, currency => waers) as ShiftedAmountunit_conversion(quantity, source_unit, target_unit)
Converts units of measure.
unit_conversion(
quantity => menge,
source_unit => meins,
target_unit => 'KG'
) as QuantityInKGcurrency_conversion(amount, source_currency, target_currency, date)
Converts currency amounts.
currency_conversion(
amount => netwr,
source_currency => waers,
target_currency => 'EUR',
exchange_rate_date => erdat
) as AmountInEURPlatform Note: unit_conversion and currency_conversion are primarily optimized for SAP HANA environments and may have limited support on other database platforms. These functions require the appropriate conversion tables (T006, TCURR) to be maintained. Verify availability with your system administrator before using in production queries.
---
Complex Function Examples
Time Formatting (Minutes to HH:MM)
concat(
concat(
lpad(ltrim(cast(div(flight_time, 60) as abap.char(12)), '0'), 2, '0'),
':'
),
lpad(ltrim(cast(mod(flight_time, 60) as abap.char(12)), '0'), 2, '0')
) as FormattedTime
-- 125 minutes = '02:05'Date Validation with Default
case
when dats_is_valid(input_date) = 1 then input_date
else '00000000'
end as ValidatedDateConditional Text Concatenation
case
when last_name is not null
then concat_with_space(first_name, last_name, 1)
else first_name
end as DisplayNamePercentage Calculation
case
when total > 0
then division(part * 100, total, 2)
else cast(0 as abap.dec(5,2))
end as Percentage---
Function Nesting
Functions can be nested for complex transformations:
upper(
replace(
ltrim(
concat_with_space(first_name, last_name, 1),
' '
),
' ',
'_'
)
) as NormalizedName
-- ' John Doe ' = 'JOHN_DOE'---
Best Practices
1. Use COALESCE for defaults: Avoid null in calculations 2. CAST for type safety: Explicit types prevent runtime errors 3. Aggregate with care: Always include GROUP BY for non-aggregated fields 4. Validate dates: Use dats_is_valid before date arithmetic 5. Consider performance: Complex functions may impact query time
---
Documentation Links
- ABAP Keyword Documentation — CDS Built-in Functions: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_f1_builtin_functions.htm
- ABAP Keyword Documentation — CDS SQL Functions: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abencds_sql_functions_v2.htm
- SAP Learning - CDS Functions: https://learning.sap.com/learning-journeys/acquire-core-abap-skills/calling-built-in-functions-in-cds-views
Last Updated: 2025-11-23
ABAP CDS Troubleshooting Guide
Common errors, warnings, and solutions for ABAP CDS development.
---
Error: SD_CDS_ENTITY105 - Missing Reference Information
Problem
Elements with data types CURR (currency amount) or QUAN (quantity) require reference information.
Error Message:
"Reference information is missing or data type is incorrect"Cause
Currency and quantity fields must reference their unit field for semantic correctness.
Solution 1: Add Semantics Annotations
-- For currency fields
@Semantics.currencyCode: true
waers,
@Semantics.amount.currencyCode: 'waers'
netwr,
-- For quantity fields
@Semantics.unitOfMeasure: true
meins,
@Semantics.quantity.unitOfMeasure: 'meins'
mengeSolution 2: Import Reference from Joined Table
define view Z_WITH_CURRENCY as select from vbak as v
inner join t001 as c on v.bukrs = c.bukrs
{
v.vbeln,
c.waers,
@Semantics.amount.currencyCode: 'waers'
v.netwr
}Solution 3: Block Inherited Annotations
If reference comes from base view but causes issues:
@Metadata.ignorePropagatedAnnotations: true
define view Z_CLEAN_VIEW as select from Z_BASE
{
field1,
@Semantics.currencyCode: true
local_waers,
@Semantics.amount.currencyCode: 'local_waers'
amount
}---
Warning: Cardinality Mismatch
Problem
Specified cardinality doesn't match actual data relationships.
Warning Message:
"The cardinality of association '_Assoc' may not match the data"Cause
[0..1]specified but multiple records exist[1..*]specified but zero records possible
Solution
Define cardinality matching actual data:
-- If truly optional single record
association [0..1] to target as _Assoc on ...
-- If multiple records possible
association [0..*] to target as _Assoc on ...
-- If always exactly one
association [1..1] to target as _Assoc on ...Verification
" Check actual cardinality in data
SELECT parent_key, COUNT(*) AS cnt
FROM child_table
GROUP BY parent_key
HAVING COUNT(*) > 1
INTO TABLE @DATA(lt_multiple).
IF lt_multiple IS NOT INITIAL.
" Multiple records exist - use [0..*] or [1..*]
ENDIF.---
Error: View Activation Failed
Problem
CDS view cannot be activated.
Common Causes and Solutions
1. SQL View Name Too Long
-- Error: SQL view name exceeds 16 characters
@AbapCatalog.sqlViewName: 'ZVERY_LONG_VIEW_NAME_HERE'
-- Solution: Shorten to max 16 characters
@AbapCatalog.sqlViewName: 'ZV_SHORT_NAME'2. Duplicate SQL View Name
-- Another view already uses this SQL view name
-- Solution: Use unique name
@AbapCatalog.sqlViewName: 'ZV_UNIQUE_123'3. Invalid Field Name
-- Reserved word or invalid characters
{
select as Select -- 'select' is reserved
-- Solution: Use valid alias
select as SelectionField
}4. Type Mismatch in UNION
-- Fields must have compatible types
define view Z_UNION as
select from table1 { cast(field as abap.char(10)) as f1 }
union
select from table2 { cast(field as abap.char(10)) as f1 }---
Error: Association Target Not Found
Problem
Association references non-existent entity.
Error Message:
"The CDS entity 'TARGET_VIEW' does not exist"Solution
1. Verify target view name spelling 2. Ensure target view is activated 3. Check target is in accessible package
-- Correct entity name
association [0..1] to I_BUSINESSPARTNER as _Partner on ...
-- NOT: I_BusinessPartner (case matters in some contexts)---
Error: Annotation Syntax Error
Problem
Invalid annotation syntax.
Common Issues
Missing Colon
-- Wrong
@AccessControl.authorizationCheck #NOT_REQUIRED
-- Correct
@AccessControl.authorizationCheck: #NOT_REQUIREDInvalid Value
-- Wrong
@AccessControl.authorizationCheck: 'NOT_REQUIRED'
-- Correct (use # for enum)
@AccessControl.authorizationCheck: #NOT_REQUIREDMissing Brackets
-- Wrong
@UI.lineItem: position: 10
-- Correct
@UI.lineItem: [{ position: 10 }]---
Error: DCL Compilation Failed
Problem
Access control definition has errors.
Common Issues
1. Wrong View Name in DCL
-- DCL references non-existent view
define role Z_WRONG_DCL {
grant select on Z_NONEXISTENT_VIEW
where ...
}
-- Solution: Verify view name
define role Z_CORRECT_DCL {
grant select on Z_EXISTING_VIEW
where ...
}2. Invalid Authorization Object
-- Authorization object doesn't exist
where (bukrs) = aspect pfcg_auth(INVALID_OBJECT, BUKRS, ACTVT = '03');
-- Solution: Verify in SU21
where (bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03');3. Field Not in View
-- Field 'xyz' not in protected view
where (xyz) = aspect pfcg_auth(...)
-- Solution: Use field that exists in view
where (bukrs) = aspect pfcg_auth(...)---
Warning: No Access Control
Problem
View has @AccessControl.authorizationCheck: #CHECK but no DCL.
Warning Message:
"No access control exists for entity 'Z_VIEW'"Solutions
Option 1: Create DCL
@MappingRole: true
define role Z_VIEW_DCL {
grant select on Z_VIEW
where ...
}Option 2: Disable Check
@AccessControl.authorizationCheck: #NOT_REQUIRED
define view Z_VIEW as select from ...---
Performance Issues
Symptom: Slow Query Execution
Causes and Solutions
1. Missing Index on Filter Fields
-- Slow: Filtering on non-indexed field
where customer_name like '%SAP%'
-- Better: Filter on indexed key field
where customer_id = 'CUST001'2. Unnecessary Joins via Associations
-- Triggers join even if not needed
{
_Customer.name1 -- Always joins
}
-- Better: Expose association only
{
_Customer -- Join-on-demand
}3. Complex CASE in WHERE
-- Slow: Complex logic in WHERE
where case when type = 'A' then field1 else field2 end = 'X'
-- Better: Restructure query or use UNION4. Wrong Cardinality
-- Slow: TO MANY when actually TO ONE
association [0..*] to customer as _Cust on ...
-- Better: Correct cardinality enables optimization
association [0..1] to customer as _Cust on ...---
Runtime Errors
CX_SY_OPEN_SQL_DB
Problem: Database error during CDS access.
Common Causes:
- Invalid data conversion
- Division by zero
- Buffer overflow
Solution: Add defensive logic:
case
when divisor = 0 then 0
else dividend / divisor
end as SafeDivisionCX_ABAP_INVALID_VALUE
Problem: Invalid value in CDS calculation.
Solution: Validate before calculation:
case
when dats_is_valid(date_field) = 1
then dats_add_days(date_field, 7)
else '00000000'
end as SafeDate---
Debugging Tips
1. Data Preview in ADT
Right-click view → Open With → Data Preview
2. Generated SQL
Right-click view → Show SQL CREATE Statement
3. Check Dependencies
Right-click view → Get Where-Used List
4. Annotation Analysis
DATA: lo_svc TYPE REF TO cl_dd_ddl_annotation_service.
cl_dd_ddl_annotation_service=>create(
EXPORTING iv_cds_view = 'Z_VIEW'
RECEIVING ro_service = lo_svc
).
DATA(lt_annos) = lo_svc->get_annos( ).5. Authorization Trace
Transaction ST01 → Authorization check trace
---
Useful Transactions
| TCode | Purpose |
|---|---|
| SE11 | Check underlying tables |
| SE16 | View table data |
| ST05 | SQL trace |
| ST01 | Authorization trace |
| SU21 | Authorization objects |
| SU53 | Last authorization failure |
| SDDLAR | Repair DDL structures |
---
Common Mistakes Checklist
- [ ] SQL view name ≤ 16 characters
- [ ] Unique SQL view name
- [ ] CURR/QUAN fields have references
- [ ] Association cardinality matches data
- [ ] DCL exists for sensitive views
- [ ] Field aliases are unique
- [ ] CASE branches return same type
- [ ] GROUP BY includes all non-aggregated fields
---
Documentation Links
- SAP Help - CDS Messages: https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abencds_messages.html
- SAP Community - CDS Troubleshooting: https://community.sap.com/t5/tag/CDS%20Views/tg-p
Last Updated: 2025-11-23
Basic CDS View Template
Standard template for creating a basic ABAP CDS view.
---
CDS View Template
@AbapCatalog.sqlViewName: 'Z<SHORT_NAME>_V'
@AbapCatalog.compiler.CompareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '<View Description>'
define view Z<VIEW_NAME>
as select from <source_table> as s
left outer join <text_table> as t
on s.<key_field> = t.<key_field>
and t.spras = $session.system_language
{
// Key fields
key s.<key_field>,
// Data fields
s.<field1>,
s.<field2>,
// Text from joined table
t.<text_field> as Description,
// Calculated fields
case s.<status_field>
when 'A' then 'Active'
when 'I' then 'Inactive'
else 'Unknown'
end as StatusText,
// Currency handling
@Semantics.currencyCode: true
s.<currency_field>,
@Semantics.amount.currencyCode: '<currency_field>'
s.<amount_field>,
// Quantity handling
@Semantics.unitOfMeasure: true
s.<unit_field>,
@Semantics.quantity.unitOfMeasure: '<unit_field>'
s.<quantity_field>,
// Administrative fields
@Semantics.user.createdBy: true
s.<created_by>,
@Semantics.systemDateTime.createdAt: true
s.<created_at>,
@Semantics.user.lastChangedBy: true
s.<changed_by>,
@Semantics.systemDateTime.lastChangedAt: true
s.<changed_at>
}---
CDS View Entity Template (7.55+)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '<View Description>'
define view entity Z<VIEW_NAME>
as select from <source_table> as s
left outer join <text_table> as t
on s.<key_field> = t.<key_field>
and t.spras = $session.system_language
{
// Key fields
key s.<key_field>,
// Data fields
s.<field1>,
s.<field2>,
// Text from joined table
t.<text_field> as Description,
// Calculated fields
case s.<status_field>
when 'A' then 'Active'
when 'I' then 'Inactive'
else 'Unknown'
end as StatusText,
// Currency handling
@Semantics.currencyCode: true
s.<currency_field>,
@Semantics.amount.currencyCode: '<currency_field>'
s.<amount_field>,
// Quantity handling
@Semantics.unitOfMeasure: true
s.<unit_field>,
@Semantics.quantity.unitOfMeasure: '<unit_field>'
s.<quantity_field>
}---
Example: Material Master View
@AbapCatalog.sqlViewName: 'ZMAT_BASIC_V'
@AbapCatalog.compiler.CompareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Basic Material View'
define view Z_MATERIAL_BASIC
as select from mara as m
left outer join makt as t
on m.matnr = t.matnr
and t.spras = $session.system_language
{
key m.matnr as Material,
m.mtart as MaterialType,
m.matkl as MaterialGroup,
m.meins as BaseUnit,
m.ersda as CreatedDate,
m.ernam as CreatedBy,
m.laeda as ChangedDate,
m.aenam as ChangedBy,
t.maktx as MaterialDescription,
case m.lvorm
when 'X' then 'Marked for Deletion'
else 'Active'
end as DeletionStatus,
@Semantics.unitOfMeasure: true
m.meins as UnitOfMeasure,
@Semantics.quantity.unitOfMeasure: 'meins'
m.ntgew as NetWeight
}---
Checklist
- [ ] SQL view name ≤ 16 characters (for CDS View)
- [ ] Unique SQL view name
- [ ] Authorization check configured
- [ ] EndUserText.label provided
- [ ] Key fields marked with
key - [ ] CURR/QUAN fields have semantic annotations
- [ ] Text join uses $session.system_language
- [ ] Aliases provided for calculated fields
---
ABAP Access
" Direct SELECT
SELECT * FROM z_material_basic
WHERE MaterialType = 'FERT'
INTO TABLE @DATA(lt_materials).
" SALV IDA Display
cl_salv_gui_table_ida=>create_for_cds_view(
CONV #( 'Z_MATERIAL_BASIC' )
)->fullscreen( )->display( ).Access Control (DCL) Template
Template for creating CDS access control definitions.
---
Basic DCL Template
@EndUserText.label: 'Access Control for <View Name>'
@MappingRole: true
define role <DCL_NAME> {
grant select on <CDS_VIEW_NAME>
where <condition>;
}---
PFCG Authorization Template
@EndUserText.label: 'Access Control for Z_VIEW'
@MappingRole: true
define role Z_VIEW_DCL {
grant select on Z_VIEW
where (<cds_field>) = aspect pfcg_auth(
<AUTH_OBJECT>,
<AUTH_FIELD>,
ACTVT = '03'
);
}---
Multiple Field Authorization
@EndUserText.label: 'Sales Organization Access Control'
@MappingRole: true
define role Z_SALES_DCL {
grant select on Z_SALES_VIEW
where (vkorg, vtweg, spart) = aspect pfcg_auth(
V_VBAK_VKO,
VKORG,
VTWEG,
SPART,
ACTVT = '03'
);
}---
Combined Conditions Template
@EndUserText.label: 'Combined Access Control'
@MappingRole: true
define role Z_COMBINED_DCL {
grant select on Z_VIEW
where
-- Authorization check
(bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03')
-- Literal condition
and status <> 'DELETED'
-- Date condition
and valid_to >= $session.system_date;
}---
User-Based Access Template
@EndUserText.label: 'Own Records Only'
@MappingRole: true
define role Z_OWN_DATA_DCL {
grant select on Z_USER_DATA
where created_by ?= aspect user;
}Note: ?= allows NULL values.
---
OR Condition Template
@EndUserText.label: 'Public or Own Records'
@MappingRole: true
define role Z_PUBLIC_OR_OWN_DCL {
grant select on Z_DOCUMENTS
where visibility = 'PUBLIC'
or created_by ?= aspect user;
}---
Multi-Level Authorization Template
@EndUserText.label: 'Multi-Level Authorization'
@MappingRole: true
define role Z_MULTILEVEL_DCL {
grant select on Z_MATERIAL_DATA
where
-- Plant authorization
(werks) = aspect pfcg_auth(M_MATE_WRK, WERKS, ACTVT = '03')
-- Material type authorization
and (mtart) = aspect pfcg_auth(M_MATE_MAR, MTART, ACTVT = '03');
}---
Common Authorization Objects Reference
Finance
| Object | Fields | Description |
|---|---|---|
| F_BKPF_BUK | BUKRS, ACTVT | Company code |
| F_BKPF_GSB | GSBER, ACTVT | Business area |
| F_BKPF_KOA | KOART, ACTVT | Account type |
| F_LFA1_BUK | BUKRS, ACTVT | Vendor company code |
| F_KNA1_BUK | BUKRS, ACTVT | Customer company code |
Sales
| Object | Fields | Description |
|---|---|---|
| V_VBAK_VKO | VKORG, VTWEG, SPART, ACTVT | Sales org/channel/division |
| V_VBAK_AAT | AUART, ACTVT | Order type |
| V_LIKP_VKO | VKORG, VTWEG, ACTVT | Delivery sales org |
Materials
| Object | Fields | Description |
|---|---|---|
| M_MATE_WRK | WERKS, ACTVT | Plant |
| M_MATE_MAR | MTART, ACTVT | Material type |
| M_MATE_MAN | MTART, ACTVT | Material maintenance |
Controlling
| Object | Fields | Description |
|---|---|---|
| K_CCA | KOKRS, KOSTL, ACTVT | Cost center |
| K_ORDER | AUFNR, ACTVT | Internal order |
| K_PCA | KOKRS, PRCTR, ACTVT | Profit center |
Important: Authorization object names and fields may vary by SAP release and customization. Always verify the correct object name and fields in your system using transaction SU21 (Maintain Authorization Objects) before implementing DCL rules.
HR
| Object | Fields | Description |
|---|---|---|
| P_ORGIN | PERSA, PERSG, ACTVT | Personnel area/group |
| PLOG | OTYPE, INFTY, ACTVT | HR master data |
---
Activity Values (ACTVT)
| Value | Activity |
|---|---|
| 01 | Create |
| 02 | Change |
| 03 | Display |
| 06 | Delete |
| 16 | Execute |
| 70 | Administration |
---
Example: Finance Document Access
@EndUserText.label: 'Finance Document Access Control'
@MappingRole: true
define role Z_FIN_DOC_DCL {
grant select on Z_FINANCE_DOCUMENTS
where
-- Company code check
(bukrs) = aspect pfcg_auth(F_BKPF_BUK, BUKRS, ACTVT = '03')
-- Business area check (optional)
and (gsber) ?= aspect pfcg_auth(F_BKPF_GSB, GSBER, ACTVT = '03')
-- Only posted documents
and posting_status = 'POSTED';
}---
Example: Sales Order Access
@EndUserText.label: 'Sales Order Access Control'
@MappingRole: true
define role Z_SALES_ORDER_DCL {
grant select on Z_SALES_ORDER
where
-- Sales organization structure
(vkorg, vtweg, spart) = aspect pfcg_auth(
V_VBAK_VKO,
VKORG,
VTWEG,
SPART,
ACTVT = '03'
)
-- Order type
and (auart) ?= aspect pfcg_auth(V_VBAK_AAT, AUART, ACTVT = '03')
-- Exclude cancelled orders
and vbtyp <> 'K';
}---
Example: Own Records with Admin Override
@EndUserText.label: 'User Tasks with Admin Access'
@MappingRole: true
define role Z_USER_TASKS_DCL {
grant select on Z_USER_TASKS
where
-- Own tasks
assigned_to ?= aspect user
-- OR admin authorization
or (admin_flag) = aspect pfcg_auth(Z_TASK_ADMIN, ADMIN, ACTVT = '03');
}---
Testing Checklist
- [ ] DCL name follows naming convention
- [ ] @MappingRole: true is set
- [ ] Correct CDS view name referenced
- [ ] Authorization objects exist (check SU21)
- [ ] Field names match CDS view exactly
- [ ] Activity value appropriate (usually '03')
- [ ] Test with authorized user
- [ ] Test with unauthorized user
- [ ] Test edge cases (NULL values)
---
Debugging
Check User Authorization (SU53)
After access denied, run SU53 to see missing authorization.
Authorization Trace (ST01)
1. Start trace in ST01 2. Execute query 3. Analyze trace for auth checks
Verify DCL Assignment
" Check if DCL exists and is assigned to view
SELECT ddlname, as4local, as4vers
FROM ddddlsrc
WHERE ddlname = 'Z_VIEW_DCL'
INTO TABLE @DATA(lt_dcl).
" Alternative: Check DCL source for specific view reference
SELECT ddlname, source
FROM ddddlsrc
WHERE source LIKE '%Z_CDS_VIEW%'
AND ddlname LIKE '%_DCL'
INTO TABLE @DATA(lt_dcl_refs).Tip: In ADT, right-click the CDS view and select Open With → Dependency Analyzer to see associated DCL objects.
Parameterized CDS View Template
Template for creating CDS views with input parameters.
---
Parameterized View Template
@AbapCatalog.sqlViewName: 'Z<SHORT_NAME>_V'
@AbapCatalog.compiler.CompareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '<View Description>'
define view Z<VIEW_NAME>
with parameters
@EndUserText.label: 'From Date'
p_date_from : abap.dats,
@EndUserText.label: 'To Date'
p_date_to : abap.dats,
@Environment.systemField: #SYSTEM_LANGUAGE
@EndUserText.label: 'Language'
p_language : spras
as select from <source_table> as s
left outer join <text_table> as t
on s.<key_field> = t.<key_field>
and t.spras = :p_language
{
key s.<key_field>,
s.<date_field>,
s.<field1>,
s.<field2>,
t.<text_field> as Description,
// Parameter values in output
:p_date_from as FilterDateFrom,
:p_date_to as FilterDateTo
}
where s.<date_field> between :p_date_from and :p_date_to---
View Entity with Parameters (7.55+)
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '<View Description>'
define view entity Z<VIEW_NAME>
with parameters
@EndUserText.label: 'From Date'
p_date_from : abap.dats,
@EndUserText.label: 'To Date'
p_date_to : abap.dats,
@Environment.systemField: #SYSTEM_LANGUAGE
p_language : abap.lang
as select from <source_table> as s
{
key s.<key_field>,
s.<date_field>,
s.<field1>,
s.<field2>
}
where s.<date_field> between $parameters.p_date_from
and $parameters.p_date_to---
Parameter Types
Common ABAP Types for Parameters
| Type | Description | Example |
|---|---|---|
abap.dats | Date | p_date : abap.dats |
abap.tims | Time | p_time : abap.tims |
abap.char(n) | Character | p_name : abap.char(40) |
abap.numc(n) | Numeric text | p_number : abap.numc(10) |
abap.int4 | Integer | p_count : abap.int4 |
abap.lang | Language | p_lang : abap.lang |
abap.clnt | Client | p_client : abap.clnt |
Data Element References
with parameters
p_matnr : matnr, -- Material number
p_bukrs : bukrs, -- Company code
p_vkorg : vkorg -- Sales organization---
Environment System Fields
Auto-populate parameters with system values:
| Annotation | Value |
|---|---|
@Environment.systemField: #SYSTEM_DATE | SY-DATUM |
@Environment.systemField: #SYSTEM_TIME | SY-UZEIT |
@Environment.systemField: #SYSTEM_LANGUAGE | SY-LANGU |
@Environment.systemField: #USER | SY-UNAME |
@Environment.systemField: #CLIENT | SY-MANDT |
with parameters
@Environment.systemField: #SYSTEM_DATE
p_date : abap.dats,
@Environment.systemField: #SYSTEM_LANGUAGE
p_language : abap.lang---
Parameter Reference Syntax
Two equivalent syntaxes:
-- Colon notation
:p_param_name
-- $parameters notation
$parameters.p_param_nameIn WHERE Clause
where date_field = :p_date
and company = $parameters.p_companyIn CASE Expression
case
when :p_show_all = 'X' then 'All'
else 'Filtered'
end as ViewModeIn Projection
{
key field1,
:p_date_from as FilterStart,
:p_date_to as FilterEnd
}---
Example: Sales Orders with Date Range
@AbapCatalog.sqlViewName: 'ZSO_DATERANGE_V'
@AbapCatalog.compiler.CompareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Orders by Date Range'
define view Z_SALES_ORDER_DATERANGE
with parameters
@EndUserText.label: 'Order Date From'
p_date_from : abap.dats,
@EndUserText.label: 'Order Date To'
p_date_to : abap.dats,
@EndUserText.label: 'Sales Organization'
p_vkorg : vkorg,
@Environment.systemField: #SYSTEM_LANGUAGE
p_language : spras
as select from vbak as h
left outer join vbap as i on h.vbeln = i.vbeln
left outer join makt as t on i.matnr = t.matnr
and t.spras = :p_language
{
key h.vbeln as SalesOrder,
key i.posnr as Item,
h.erdat as OrderDate,
h.vkorg as SalesOrg,
h.kunnr as Customer,
i.matnr as Material,
t.maktx as MaterialDescription,
@Semantics.currencyCode: true
h.waerk as Currency,
@Semantics.amount.currencyCode: 'Currency'
i.netwr as NetValue,
@Semantics.unitOfMeasure: true
i.meins as Unit,
@Semantics.quantity.unitOfMeasure: 'Unit'
i.kwmeng as Quantity,
:p_date_from as FilterDateFrom,
:p_date_to as FilterDateTo
}
where h.erdat between :p_date_from and :p_date_to
and h.vkorg = :p_vkorg---
ABAP Access with Parameters
Basic SELECT
DATA: lv_date_from TYPE dats VALUE '20240101',
lv_date_to TYPE dats VALUE '20241231'.
SELECT * FROM z_sales_order_daterange(
p_date_from = @lv_date_from,
p_date_to = @lv_date_to,
p_vkorg = '1000',
p_language = @sy-langu
)
INTO TABLE @DATA(lt_orders).With Inline Literals
SELECT * FROM z_sales_order_daterange(
p_date_from = '20240101',
p_date_to = '20241231',
p_vkorg = '1000',
p_language = 'E'
)
INTO TABLE @DATA(lt_orders).Dynamic Parameter Binding
DATA: lt_params TYPE abap_parmbind_tab,
lt_orders TYPE STANDARD TABLE OF z_sales_order_daterange.
lt_params = VALUE #(
( name = 'P_DATE_FROM' kind = cl_abap_objectdescr=>exporting value = REF #( lv_date_from ) )
( name = 'P_DATE_TO' kind = cl_abap_objectdescr=>exporting value = REF #( lv_date_to ) )
( name = 'P_VKORG' kind = cl_abap_objectdescr=>exporting value = REF #( lv_vkorg ) )
( name = 'P_LANGUAGE' kind = cl_abap_objectdescr=>exporting value = REF #( sy-langu ) )
).
" Dynamic SELECT with parameters
SELECT * FROM z_sales_order_daterange
USING CLIENT @sy-mandt
INTO TABLE @lt_orders
WHERE (lv_where_clause).Note: Dynamic parameter binding is complex and typically used in generic frameworks. For most use cases, direct parameter passing (as shown above) is simpler and recommended.
---
Checklist
- [ ] All parameters have meaningful names (p_ prefix)
- [ ] EndUserText.label for each parameter
- [ ] Environment annotations for system fields
- [ ] Correct data types for parameters
- [ ] Parameters used in WHERE clause or output
- [ ] Tested with various parameter combinations
- [ ] NULL handling for optional parameters
Related skills
FAQ
What does sap-abap-cds help developers build?
sap-abap-cds helps author and refine ABAP Core Data Services views and entities that model ERP data and expose analytical and transactional interfaces in S/4HANA.
Is sap-abap-cds for non-SAP projects?
No—sap-abap-cds is scoped to SAP ABAP CDS work in ERP and S/4HANA landscapes, not general PostgreSQL or REST API greenfield apps.