Dieser Spickzettel enthält eine umfassende Übersicht über Syntax, Beispiele und Beschreibungen zu CDS ABAP. Wir verwenden diese auch in unserer CDS ABAP Schulung bei Brandeis Consulting.
Diese Übersicht zeigt nur die wichtigsten Aspekte und ist nicht komplett. Für Details bitte den Links zur SAP Dokumentation oder den verlinkten Quellen folgen. Die Beispiele beziehen sich auf die Folien aus der Schulung.
Bei CDS ABAP spielt grundsätzlich das Release des ABAP Servers eine große Rolle, da hier noch viel in Bewegung ist. Die Beispiele wurden auf Release 7.58 (S/4HANA 2023) erstellt. Bei einem Blick in die Dokumentation sollten Sie stets exakt Ihren Versionsstand wählen.
Mit ABAP 7.55 hat die SAP die CDS View Entities veröffentlicht. Damit wurden die bisherigen CDS Views zu DDIC-based CDS Views umbenannt und diese sind seit 7.57 auch obsolet.
Unterschiede in CDS View Entities:
@AbapCatalog.sqlViewName entfälltDEFINE VIEW heißt es DEFINE VIEW ENTITY
Empfehlungen
Bezeichner von Tabellen, Views oder Spalten sind nicht case-sensitive. Sie dürfen maximal 30 Zeichen lang sein und bestehen aus Buchstaben, Zahlen, Unterstrichen und Schrägstrichen.
Zeichenliterale kommen in Hochkommata. Numerische Literale einfach hinschreiben, ggf. mit Dezimalpunkt.
Kommentare können entweder am Zeilenende mit einem doppelten Schrägstrich // beginnen oder als Blockkommentare zwischen /* und */ platziert werden.
Whitespace spielt keine große Rolle und dient in erster Linie zum Formatieren, solange die Semantik eindeutig ist.
Punkte werden zwischen Tabellennamen (auch Alias) und Feldnamen verwendet. z.B. mara.matnr.
Mit Annotationen wird der Quelltext um Meta-Informationen angereichert. Sie sind für die Konsumenten der CDS Objekte relevant. Jedes Framework hat seine eigenen Annotationen, z.B. :
@Analytics@Consumtion@ObjectModel@OData@UIHier sind nur zu wenigen Themen eine Auswahl von Annotationen erwähnt. Die komplette Liste ist in der SAP Dokumentation.
Syntax der Annotationen
@Annotation: <value>
@Annotation.SubAnnotation.SubSubAnnotation: <value>
@Annotation: { SubAnnotation1: <value1>,
SubAnnotation2: <value2> }
Werte einer Annotation
# beginnend, Code-Completion nutzen!true und falseDEFINE VIEW CDSEntity
[...PARAMETER...]
AS SELECT FROM <sources>
[...JOIN..]
[...ASSOCIATION..]
{
[KEY] ... [ AS ... ]
[,...]
}
[WHERE ...]
[GROUP BY ...
[HAVING ...]]
[UNION ...]
Die Feldliste besteht aus Ausdrücken. Das sind meistens Feldnamen der Quellen. Es können aber auch andere Elemente darin vorkommen. Möglich sind:
<Quelle>.<Feldname>Die Ausdrücke können ineinander geschachtelt werden. Beispielsweise kann ein Parameter als Vergleichswert in einem CASE - Ausdruck verwendet werden.
Die einzelnen Felder werden durch Komma getrennt. Falls sich nicht auf einen Feldnamen bezogen wird, ist ein mit AS vergebener Aliasname für das Feld Pflicht. Das Schlüsselwort KEY markiert den Schlüssel.
![]()
Schulungen und Beratung vom Autor des Buches SQLScript für SAP HANA. Bei Fragen zur SQLScript, CDS ABAP oder unseren Schulungen einfach eine Mail an info@brandeis.de schicken.
© Brandeis Consulting GmbH
Die Typisierung in CDS bezieht sich entweder auf
abap.<Type>Die Datentypen werden an vielen Stellen streng geprüft und es gibt ggf. beim Aktivieren des CDS ABAP Objektes Fehlermeldungen. Zum Konvertieren der Datentypen dient die SQL-Funktion CAST:
CAST( <Expr> AS <Type> [PRESERVING TYPE])
Die ABAP Datentypen werden dabei mit abap.<Type> angegeben, also Beispielsweise
abap.int4abap.char(<Length>)abap.dec(<Length>, <Nachkommastellen>)Je nach Datentyp muss die <Length> und ggf. auch die Anzahl <Nachkommastellen> in Klammern angegeben werden. Falls der Datentyp des <Expr> identisch mit dem angegebenen Datenelement ist (z.B. WAERS zu TRAN_CURR ), erleichtert der Zusatz PRESERVING TYPE das Lesen.
Es gibt eine Hand voll Session-Variablen, auf die man in CDS SQL mit dieser Syntax zugreifen kann:
$session.<Variablenname>
Bislang gibt es die folgenden Variablennamen, die weitgehend Komponenten der SY bzw. SYST Struktur im ABAP entsprechen:
SY-UNAME.SY-MANDTSY-LANGUSY-DATUMSY-ZONLOSY-DATLOIn CDS ABAP funktionieren die Rechenoperatoren für Addition (+), Subtraktion (-), Multiplikation (*) wie man es erwarten würde. Grundsätzlich ist vor und nach dem Divisionsoperator (/) ein Whitespace notwendig. Die Berechnungen sind intern sehr genau. Beim CAST auf kleinere Datentypen werden Stellen abgeschnitten. Hier muss vorher mit der Funktion ROUND entsprechend gerundet werden.
CASE - AusdrückeEin CASE - Ausdruck in CDS ABAP liefert je nach den Bedingungen immer genau einen Wert zurück. Der einfache CASE - Ausdruck vergleicht einen Ausdruck mit mehreren anderen Ausdrücken auf Gleichheit:
CASE item_categ WHEN '10' THEN 'A'
WHEN '20' THEN 'B'
ELSE 'C'
END
Der komplexe CASE - Ausdruck (engl. searched case) wertet N unabhängige Bedingungen aus. Die erste, die zu TRUE ausgewertet wird, liefert das Ergebnis:
CASE WHEN priority >= 9 THEN 'A'
WHEN priority >= 6 THEN 'B'
ELSE 'C'
END
Wenn keine Bedingung zu TRUE ausgewertet wurde, wird entweder der Wert aus der ELSE -Klausel oder NULL zurückgegeben.
Assoziationen beschreiben die Beziehungen zwischen den CDS-Entitäten untereinander. Sie definieren einen JOIN, der nur bei Bedarf ausgeführt wird. Die Abfragen erfolgen mit sogenannten Pfadausdrücken und können über mehrere CDS-Entitäten hinweg erfolgen.
define view entity ZI_Users
as select from zbc_users
association of one to many to ZI_Tasks as _TasksToDo
on $projection.UserId = _TasksToDo.Assignee
association [0..*] ZI_Tasks as _TasksCreated
on $projection.UserId = _TasksCreated.Author
{
key user_id as UserId,
firstname as Firstname,
lastname as Lastname,
// ...
_TasksToDo,
_TasksCreated
}
Die Namen der Assoziationen beginnen immer mit einem Unterstrich. Sie werden mit in die Feldliste aufgenommen und somit für die Nutzer des CDS-Views verfügbar gemacht.
Die Kardinalität kann in eckigen Klammern angegeben werden:
association [Min..Max] to ..., möglich sind 0, 1, *
Ab ABAP 7.58 kann man auch die folgende Syntax nutzen:
association of [many|one|exact one] to [many|one|exact one] ...
Je nach Framework haben Assoziationen unterschiedliche Wirkung
Mit Pfadausdrücken können Felder aus assoziierten Views in die Feldliste des CDS Views oder der Abfrage auf die CDS Entität aufgenommen werden. Die Pfadausdrücke können auch über mehrere Views gehen. Und es ist möglich, entlang des Pfades zu filtern:
In CDS SQL
_TasksToDo.TaskKey,
_TasksToDo._Author.Lastname,
_TasksToDo[ Status = 'NEW' ].Summary,
In ABAP SQL
Die Pfadausdrücke können in ABAP SQL genutzt werden. Allerdings ist die Syntax etwas anders. Vor Assoziationen, und als Trennzeichen dazwischen, kommt immer der Backslash (\). Die Komponente wird, wie in ABAP üblich, mit dem Bindestrich (-) angesprochen:
\_TasksToDo\TaskKey,
\_TasksToDo\_Author.Lastname,
\_TasksToDo[ Status = 'NEW' ]-Summary,
In der Datenbank gibt es den Pseudo-Wert NULL, der für die Abwesenheit eines Wertes steht. Dieser wird im ABAP in einen initialen Wert übersetzt. Das kann beim Aggregieren zu unerwarteten Situationen führen, da für NULL und Initialwert im CDS ABAP zwei Gruppen gebildet werden, die im ABAP aber beide initial sind.
Ersetzen von NULL
Mit der SQL-Funktion COALESCE(<Wert1>, <Wert2>) kann man NULL Werte abfangen, da diese dann den 2. Wert zurückgibt.
Filtern mit NULL
Ein normaler Vergleich mit NULL ergibt immer den logischen Wert UNKNOWN. Damit ist ein solcher Vergleich in der WHERE Bedingung niemals erfüllt. Deswegen muss das Prädikat IS (NOT) NULL verwendet werden.
Leerzeichen am Ende der Zeichenketten (<ZK>) werden in CDS SQL teilweise entfernt.
| SQL function | Description |
|---|---|
CONCAT(<Str1>, <Str2>) | Kombiniert <Str1> und <Str2> |
CONCAT_WITH_SPACES( <Str1>, <Str2>, <Cnt>) | Kombiniert <Str1> und <Str2> mit <Cnt> Leerzeichen |
LENGTH(<Str>) | Länge der Zeichenkette |
LOWER(<Str>) | In kleinbuchstaben |
UPPER(<Str>) | In GROSSBUCHSTABEN |
LEFT(<Str>, <Len>) | Linker Teil von <Str> mit <Len> |
RIGHT(<Str>, <Len>) | Rechter Teil von <Str> mit <Len> |
SUBSTRING(<Str>, <Pos>, <Len>) | Substring ab <Pos> mit <Len> |
INSTR(<Str1>, <Str2>) | Position von <Str2> in <Str1> |
REPLACE(<Str1>, <Str2>, <Str3>) | Ersetzt <Str2> in <Str1> mit <Str3> |
REPLACE_REGEXPR( PCRE => <Regex>, VALUE => <Str>, WITH => <Repl>, RESULT_LENGTH => <Len>,[OCCURRENCE],[CASE_SENSITIVE],[SINGLE_LINE],[MULTI_LINE],[UNGREEDY] ) | Ersetzt die PCRE <Regex> im String <Str> mit dem <Repl>. Parameter werden im Format Name => <Wert> übergeben. OCCURENCE: 1-N oder ALL. Flags haben den Wert '' oder 'X'. |
LPAD(<Str> , <Len> , <Pat>) | Füllt <Str> von links mit <Pat> bis zur <Len> auf |
RPAD(<Str>, <Len>, <Pat>) | Füllt <Str> von rechts mit <Pat> bis zur <Len> auf |
LTRIM(<Str> , <Char>) | Entfernt führende <Char> in <Str>, z.B. Nullen oder Space |
RTRIM(<Str>, <Char>) | Entfernt rechts alle <Char> in <Str> |
Kürzel: Zahl oder Zähler (<Z>), Nenner (<N>) und Nachkommastellen (<NK>).
| SQL function | Description |
|---|---|
ROUND(<Z>, <NK>) | Kaufmännische Rundung auf <NK> Stellen |
CEIL(<Z>) | Rundung auf... |
FLOOR(<Z>) | ...oder ab zur nächsten ganzen Zahl |
DIVISION(<Z>, <N>, <NK>) | <Z> dividiert durch <N>, gerundet auf <NK> Stellen |
DIV(<Z>, <N>) | Ganzzahliger Anteil der Division <Z> durch <N> |
MOD(<Z>, <N>) | Rest der Division <Z> durch <N> (Modulo) |
ABS(<Z>) | Positiver Absolutwert von <Z> |
UNIT_CONVERSION | Mengenumrechnung |
CURRENCY_CONVERSION | Währungsumrechnung |
DECIMAL_SHIFT | Dezimalverschiebung |
Die SQL-Funktionen im CDS ABAP sind eine Teilmenge derer, die auch im OpenSQL in ABAP zur Verfügung stehen. Die Datentypen werden bei diesen SQL-Funktionen grundsätzlich vorangestellt, z.B.:
DATS ist der bekannte ABAP Datentyp, für die DB nur CHAR(8)DATN ist das SQL-Datumsformat der HANA - für ABAP wenig relevantTIMS ist der ABAP Datentyp für Zeit, für die DB nur CHAR(8)TIMN ist das SQL-Zeitformat der HANA, siehe DATNTSTMP ist der kurze Timestamp, 15-Stellige DezimalzahlTSTMPL ist der lange Zeitstempel mit 7 NK Stellen.UTCL entspricht dem ABAP Datentyp UTCLONG, intern 8 ByteDie Namen der CDS ABAP SQL- Funktionen beginnen mit dem Datentypen. Hier nur ein Auszug der wichtigsten Funktionen.
Konvertierungen
DATS_TIMS_TO_TSTMPTSTMP_TO_DATSTSTMP_TO_DSTTSTMP_TO_TIMSTSTMPL_TO_UTCLTSTMPL_FROM_UTCLAddition
DATS_ADD_DAYSDATS_ADD_MONTHSTSTMP_ADD_SECONDSUTCL_ADD_SECONDSDifferenzen
UTCL_SECONDS_BETWEENTSTMP_SECONDS_BETWEENDATS_DAYS_BETWEENAktueller Zeitpunkt
UTCL_CURRENTTSTMP_CURRENT_UTCTIMESTAMPABAP_SYSTEM_TIMEZONEABAP_USER_TIMEZONEFür einen CDS ABAP View können Parameter definiert werden, die dann als Ausdruck verwendet werden als
WHERE, z.B. Sprache filtern oderAuf Parameter wird mit der $parameters Struktur zugegriffen
define view entity zi_Parameter
with parameters
Vat : abap.int1,
Language : abap.lang,
DisplayCurrency : abap.cuky( 5 )
as select from <Table>
{
key Task_key as Keyfield,
Amount * (1 + (100 + $parameters.Vat)
/ 100 ) as GrossAmount,
currency_conversion(
target_currency => $parameters.DisplayCurrency
... )
} where Language = $parameters.Language
Delta Extraktion mit Zeitstempelfeld
Das Delta wird über ein Zeitstempelfeld mit der Annotation @Semantics.SystemDateTime.LastChangedAt: true gebildet.
@Analytics:{ dataCategory: #CUBE
dataExtraction:{
enabled: true,
delta.byElement: {
name:'LastChangedAt'
} } }
Change Data Caption (CDC)
Automatische Änderungserfassung auf Systemen ab SAP S/4HANA 1909 FPS01 möglich. Bei komplexeren Szenarien mit JOINs muss explizit gemappt werden. Details im sehr lesenswerten Blog von Simon Kranig.
@Analytics:{
dataCategory: #DIMENSION
dataExtraction: {
enabled: true,
delta.changeDataCapture: {
automatic : true
} } }
CDS Table Functions sind in SQLScript programmierte Views. Sie basieren auf einer AMDP-Funktion, die durch ein CDS ABAP Objekt gekapselt wird.
Die CDS-Table Function definiert die Signatur:
@EndUserText.label: 'My Table Function'
DEFINE TABLE FUNCTION zjb_demo_tf
RETURNS
{
mandt : abap.clnt;
doc_number : /bi0/oidoc_number;
net_price : /bi0/oinet_price;
}
IMPLEMENTED BY
METHOD zcl_demo_tf=>my_tf;
Die AMDP Tabellenfunktion dazu:
CLASS zcl_demo_tf DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS my_tf
FOR TABLE FUNCTION zjb_demo_tf.
ENDCLASS.
CLASS zcl_demo_tf IMPLEMENTATION.
METHOD my_tf BY DATABASE FUNCTION
FOR HDB LANGUAGE SQLSCRIPT
USING <sourceTable>.
RETURN SELECT mandt,
doc_number,
SUM( net_price )
AS net_price
FROM <sourceTable>
GROUP BY doc_number;
ENDMETHOD.
ENDCLASS.
Basis für CDS Queries sind CDS InfoProvider mit der Annotation @Analystics.dataCateogory: [#CUBE | #DIMENSION]
Sie bilden einen transienten InfoProvider mit dem Namen 2C<SQLView Name>. Sie enthalten die vollständigen semantischen Informationen des Datenmodells, welches die CDS Queries später verwenden sollen.
CDS Cube Views sind die Basis von Kennzahlenberichten. Sie können zusätzliche CDS Dimension Views assoziieren, um die Attribute und Texte von Merkmalen anzureichern.
@Analytics.dataCategory: #CUBE
DEFINE VIEW zjb_demo_cube
AS SELECT FROM <Quelle>
ASSOCIATION TO zjb_material_dim AS _Mat
ON $projection.material = _Mat.material
{
...
@ObjectModel.foreignKey.association: '_Mat'
material,
...
}
Die CDS Dimension Views liefern Attribute zu einem Merkmal. Diese Attribute können zeitabhängig sein.
@Analytics.dataCategory: #DIMENSION
@ObjectModel.representativeKey: 'material'
DEFINE VIEW zjb_material_dim
AS SELECT FROM /bi0/pmaterial AS dim
ASSOCIATION [*] TO zjb_mat_txt AS _MatText
ON dim.material = _MatText.material
{
@ObjectModel.text.association: '_MatText'
KEY material,
...
}
Die CDS Text Views liefern die sprachabhängigen Texte zu Feldern.
@ObjectModel.dataCategory: #TEXT
@ObjectModel.representativeKey: 'material'
DEFINE VIEW zjb_material_txt
AS SELECT FROM /bi0/tmaterial
{
KEY material,
@Semantics.language: true
KEY langu,
@Semantics.text: true
txtmd
}
Quelle für eine CDS Query View ist immer ein CDS InfoProvider View. Mit der CDS ABAP Annotation @Analytics.query: true wird aus einem View ein CDS Query View.
@Analytics.query: true
@Analytics.settings.zeroValues: {
handling: #HIDE_IF_ALL, //#HIDE, #SHOW
hideOnAxis: #ROWS_COLUMNS//#COLUMNS,#ROWS
}
Filter mit Prompt
@Consumption.filter:{
selectionType: #RANGE,//#INTERVAL,#SINGLE
//#HIERARCHY_NODE
multipleSelections: false,
mandatory: true,
defaultValue: '0000000000011675' }
AnalyticDetails für Merkmale
@AnalyticsDetails.query:{
display: #KEY, //#KEY_TEXT,#TEXT
axis: #ROWS, //#COLUMNS
totals: #HIDE, //#SHOW
sortDirection: #ASC } //#DESC
AnalyticDetails für Kennzahlen
@AnalyticsDetails.query:{
decimals: 0 ,
hidden: false
formula: ' a - b ' }
1 AS a_minus_b,
@EndUserText.label: 'number of records'
@AnalyticsDetails.exceptionAggregationSteps:
[{ exceptionAggregationBehavior: #COUNT,
exceptionAggregationElements:
['doc_number'] }]
1 AS doc_count