Cheat Sheet CDS ABAP

 Die perfekte Ergänzung zu den Schulungen von Brandeis Consulting

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.53 erstellt. Bei einem Blick in die Dokumentation sollten Sie stets exakt Ihren Versionsstand wählen.


Unter der Linie sind Referenzen zur

3 Objekte von klassischen CDS Views

Für CDS Views werden drei unterschiedliche Objekte im Objektkatalog (Tabelle TADIR) angelegt: 

  • DDL-Datei – Die Quelltextdatei , die mit den ADT in Eclipse angelegt und bearbeitet wird. Nur dieses Objekt steht in der Objektliste der Transportaufträge (Objekttyp DDLS). 
  • CDS-Entität – Das CDS Objekt, das alle Eigenschaften des Views, inklusive der Annotationen, Assoziationen und Berechtigungsprüfung repräsentiert. Dieses Objekt wird in ABAP Programmen verwendet. 
  • SQL-Datenbankview – Ein Datenbankview, der auch im DDic als View angezeigt wird, aber aus ABAP Perspektive nicht genutzt werden soll.

Die DDL-Datei und die CDS-Entität haben meistens den gleichen technischen Namen. Der SQL-Datenbankview muss einen anderen Namen als die CDS-Entität haben, da beide im gleichen Namensraum befinden. 

Mit dem Release 7.55 ist neben dem klassischen CDS View ein neuer Objekttyp hinzugekommen, die CDS View Entity . Dieser hat keinen SQL-Datenbankview. Es wird von der SAP empfohlen, diese Objekte zu verwenden, falls man auf dem entsprechenden Systemstand ist. 

Syntax Grundlagen

Schlüsselwörter in CDS ABAP werden entweder 

  • komplett in GROSSBUCHSTABEN oder 
  • komplett in Kleinbuchstaben oder
  • der erste Buchstabe groß und der Rest klein geschrieben

Bezeichner von Tabellen, Views oder Spalten sind nicht case-sensitive. Sie dürfen maximal 30 Zeichen lang sein und bestehen aus Buchstaben, Zahlen, Unterstrich und Schrägstrich.

Zeichenketten werden als Literale im Quelltext in Hochkommata gesetzt. Numerische Literale ohne Dezimaltrennzeichen sind je nach Wert vom Typ ABAP.INT1 bis ABAP.INT8. Numerische Literale mit dem Punkt als Dezimaltrennzeichen sind vom Datentyp ABAP.FLTP

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.  

Annotationen

Mit Annotationen wird der Quelltext um Meta-Informationen angereichert. Sie sind zum einen für die Generierung der Views und zum anderen für die Konsumenten der CDS ABAP Objekte relevant. Jedes Framework hat seine eigenen Annotationen für die CDS Views, z.B. : 

  • @Analytics
  • @Consumtion
  • @EnterpriseSearch
  • @ObjectModel
  • @OData
  • @UI

In diesem Plakat sind die zu den Themen wichtigsten Annotationen erwähnt. Die komplette Liste mit über 800 Annotationen finden Sie in der SAP Dokumentation

Syntax der Annotationen

@Annotation: Wert
@Annotation.SubAnnotation.SubSubAnnotation: Wert
@Annotation: { SubAnnotation1: Wert1,
               SubAnnotation2: Wert2 }

Werte einer Annotation

  • Einzelne Literale, z.B. die Referenz auf einen anderen Feldnamen
  • Einzelwerte mit vorab definierten Festwerten. Diese beginnen mit einem # und werden von der Code-Completion vorgeschlagen.  
  • Einzelne logische Werte true und false
  • Arrays als Liste von Werten oder SubAnnotationen, in eckigen Klammern mit Kommata getrennt

Syntaxübersicht CDS Views 

@AbapCatalog.sqlViewName: 'SQLDatenbankView'
DEFINE VIEW CDSEntität
  [ParameterDefinition]
  AS SELECT FROM <Quellen>
  [Joins]
  [Assoziationen]
  {
  [KEY] Ausdruck [ AS Feldname ]
  [,...]
  } 
[WHERE-Klausel]
[GROUP BY-Klausel]
[HAVING-Klausel]
[UNION-Operation]

Die hier beschriebene Syntax ist weitgehend identisch für CDS Views und CDS View Entities. Es gibt zwei wichtige Unterschiede bei den View Entities: 

  • Die Annotation @AbapCatalog.sqlViewName entfällt
  • Statt DEFINE VIEW heißt es DEFINE VIEW ENTITY

Ausdrücke in der Feldliste

Die Feldliste besteht aus Ausdrücken. Das sind meistens Feldnamen der Quellen. Es können aber auch andere Elemente darin vorkommen. Möglich sind: 

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. 

SQLScript Übersicht

Brandeis Consulting

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.

(C) Brandeis Consulting GmbH

Datentypen in CDS ABAP und Casting

In den CDS Entitäten kann man sich auf die Datenelemente des Data Dictionary beziehen oder direkt auf die ABAP Datentypen. Die Datentypen müssen immer exakt passen, sonst gibt es beim Aktivieren des CDS ABAP Objektes Fehlermeldungen. Zum Konvertieren der Datentypen dient die SQL-Funktion CAST:

CAST( Ausdruck AS Datentyp [PRESERVING TYPE])

Die ABAP Datentypen werden dabei mit abap.Datentyp angegeben, also Beispielsweise

  • abap.int4 
  • abap.char(Länge)
  • abap.dec(Länge, Nachkommastellen)

Je nach Datentyp muss die Länge und ggf. auch die Anzahl Nachkommastellen in Klammern angegeben werden. Falls der Datentyp des Ausdrucks technisch identisch mit dem angegebenen Datenelement ist, kann man den Zusatz PRESERVING TYPE angeben. 

Session-Variablen

Es gibt eine Hand voll Session-Variablen, auf die man in CDS ABAP zugreifen kann. 

$session.Variablenname

Bislang gibt es die folgenden Variablennamen, die weitgehend Komponenten der SY bzw. SYST Struktur im ABAP entsprechen: 

  • USER – Der angemeldete ABAP Benutzer, entspricht SY-UNAME
  • CLIENT – Der für die Abfrage zu verwendende Mandant. Entspricht SY-MANDT, außer bei Zugriffen mit USING CLIENT oder in AMDP mit AMDP OPTIONS CDS SESSION CLIENT 
  • SYSTEM_LANGUAGE – Die Anmeldesprache im internen ABAP Format, entspricht SY-LANGU
  • SYSTEM_DATE – Aktuelles Systemdatum, entspricht SY-DATUM
  • SYSTEM_TIMEZONE – Zeitzone des Benutzers, entspricht SY-ZONLO
  • USER_DATE – Aktuelles Datum des Benutzers, entspricht SY-DATLO

Rechnen und Operatorausdrücke

In CDS ABAP funktionieren die Rechenoperatoren für Addition (+), Subtraktion (-) und Multiplikation (*) wie man es erwarten würde. Die Division unterscheidet sich hiervon aber. Grundsätzlich ist vor und nach dem Divisionsoperator (/) ein Whitespace notwendig. 

  • Bei Operatorausdrücken mit ABAP.FLTP müssen beide Operanden diesen Datentyp haben. Das stört insbesondere, da Literale mit Dezimalstellen vom Typ ABAP.FLTP sind. Hier hilft nur ein CAST.
  • Die Division mit dem Divisionsoperator (/) ist in klassischen CDS-Views nur für Gleitkomma-Datentypen erlaubt. Deshalb die SQL-Funktion DIVISION( Zähler, Nenner, NK-Stellen) verwenden, die gleich rundet.
  • Bei Berechnungen, die eine Dezimalzahl ergeben, wird geprüft, ob das Ergebnis immer in den ABAP.DEC Datentyp passt. Also maximal 31 Stellen, davon 14 Nachkommastellen. Falls das nicht der Fall ist, müssen die Operanden vorher per CAST verkleinert werden. 

CASE-Ausdrücke

Ein 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 weight_measure < 1 
       OR weight_unit = 'g' THEN 'A'
       WHEN weight_measure >= 1 
       AND weight_measure <= 5 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

Mit Assoziationen können die Beziehungen zwischen den CDS-Entitäten untereinander beschrieben werden. Sie definieren einen JOIN, der nur dann ausgeführt wird, wenn Felder von der assoziierten Entität abgefragt werden. Diese Abfragen erfolgen mit sogenannten Pfadausdrücken und können über mehrere CDS-Entitäten hinweg erfolgen. 

DEFINE VIEW zcds_as_soi  //SalesOrderItem
    AS SELECT FROM snwd_so_i AS soi
    ASSOCIATION [1] TO snwd_pd AS _product 
    ON soi.product_guid = _product.node_key
    ASSOCIATION [1] TO zcds_as_so AS _sales_order 
    ON soi.parent_key = _sales_order.NodeKey
{
FeldListe
...
_product, 
_sales_order
}

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. 

In eckigen Klammern kann die Kardinalität angegeben werden: [Min..Max]. Wenn man nur Max angibt, wird für den Min-Wert 0 angenommen. Standardmäßig ist sie [0..1]. Erlaubte Werte sind z.B. [1], [*], [1..1], [1..*] oder  [0..*].

Pfadausdrücke

Mit Pfadausdrücken können Felder aus assoziierten Quellen in die Feldliste des CDS Views oder der Abfrage auf die CDS Entität aufgenommen werden. Die Pfadausdrücke können auch über mehrere Ebenen gehen. Und es ist möglich, der Auswertung der Assoziationen auch noch Attribute mitzugeben, um beispielsweise zu filtern oder den Join-Typ festzulegen:

_sales_order.BillingStatus,
_sales_order._buyer.company_name
_sales_order._buyer[LEFT OUTER 
         WHERE legal_form = 'GmbH'].company_name

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:

SELECT \_sales_order\_buyer[LEFT OUTER
          WHERE legal_form = 'GmbH']-company_name
FROM zcds_my_view
INTO TABLE @DATA(lt_tmp).

NULL in CDS ABAP und ABAP

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. 

 

SQL-Funktionen für Zeichenketten

Vorsicht mit Leerzeichen am Anfang oder am Ende der Zeichenketten (ZK). Diese werden teilweise entfernt. Ein Blick in die Dokumentation ist hier unerlässlich!

SQL-FunktionBeschreibung
CONCAT(ZK1, ZK2)Verketten von ZK1 und ZK2.
CONCAT_WITH_SPACES( ZK1, ZK2, Anzahl)Verketten von Zeichenketten ZK1 und ZK2 mit einer Anzahl von Leerzeichen. 
LENGTH(ZK)Länge der Zeichenkette ZK
LOWER(ZK)Konvertierung der Zeichenkette ZK in Klein- / Großbuchstaben
UPPER(ZK)
LEFT(ZK, Länge)Linker/Rechter Teil der Zeichenkette ZK mit der Länge
RIGHT(ZK, Länge)
SUBSTRING(ZK,Pos,Länge)Teilzeichenkette ab Position in der Länge
INSTR(ZK1, ZK2)Position von ZK2 in ZK1

REPLACE(ZK1, ZK2, ZK3)

Ersetzt ZK2 in ZK1 durch ZK3

REPLACE_REGEXPR(
  PCRE => Regex,
  VALUE => ZK,
  WITH => Ersatz,
  RESULT_LENGTH =>Länge,

Optionale Parameter: 
  OCCURRENCE ,
  CASE_SENSITIVE ,
  SINGLE_LINE ,
  MULTI_LINE ,
  UNGREEDY )

Ersetzt den Perl kompatiblen, Regulären Ausdruck Regex in der Zeichenkette ZK mit dem Ersatz. Funktionieren nicht in klassischen CDS Views, nur in CDS View Entities.

Alle Parameter werden im Format Name => Wert angegeben. 

OCCURENCE: 1-N oder 'ALL'. Die  Flags haben den Wert '' oder 'X'

LPAD(ZK, Länge, Muster)Auffüllen der ZK von Links/Rechts mit Muster bis zur Länge
RPAD(ZK, Länge, Muster )
LTRIM(ZK, Zeichen])Entfernen aller Vorkommen eines Zeichens von Links bzw. Rechts der ZK, z.B. führende 0 oder Leerzeichen.
RTRIM(ZK, Zeichen ])

Numerische SQL-Funktionen 

Kürzel: Zahl oder Zähler (Z), Nenner (N) und Nachkommastellen (NK). 

SQL-FunktionBeschreibung
ROUND(Z, NK)Kaufmännische Rundung NK-Stellen
CEIL(Z)Auf-/Abrunden von Z auf die nächste ganze Zahl
FLOOR(Z)
DIVISION(Z, N, NK)Z geteilt durch N gerundet auf NK-Stellen
DIV(Z, N)Ganzzahliger Anteil der Division
MOD(Z, N)Rest der Division von Z durch N
ABS(Z)Positiver Absolutwert von Z

Datums- und Zeitberechnung

Die Funktionen in den CDS ABAP sind die gleichen, die auch im OpenSQL in ABAP zur Verfügung stehen. Die Datentypen spielen bei den SQL-Funktionen eine große Rolle, weshalb deren Kürzel grundsätzlich vorangestellt wird, z.B.:

  • DATS ist der bekannte ABAP Datentyp, für die DB nur CHAR(8)
  • DATN ist das SQL-Datumsformat der HANA
  • TIMS ist der ABAP Datentyp für Zeit
  • TIMN ist das SQL-Zeitformat der HANA
  • TSTMP ist der kurze Timestamp, 15-Stellige Dezimalzahl
  • TSTMPL ist der lange Zeitstempel mit 7 NK Stellen.
  • UTCL entspricht dem ABAP Datentyp UTCLONG, intern 8 Byte 

Die Namen der CDS ABAP SQL- Funktionen beginnen mit dem Datentypen.

Konvertierungen

  • DATS_TO_DATN
  • DATS_FROM_DATN
  • TIMS_TO_TIMN
  • TIMS_FROM_TIMN
  • DATS_TIMS_TO_TSTMP
  • TSTMP_TO_DATS
  • TSTMP_TO_DST
  • TSTMP_TO_TIMS
  • TSTMPL_TO_UTCL
  • TSTMPL_FROM_UTCL

Gültigkeit

Ergeben 1 falls gültig, sonst 0.

  • TSTMP_IS_VALID
  • TIMS_IS_VALID
  • DATS_IS_VALID

Addition

  • DATN_ADD_DAYS
  • DATN_ADD_MONTHS
  • DATS_ADD_DAYS
  • DATS_ADD_MONTHS
  • TSTMP_ADD_SECONDS
  • UTCL_ADD_SECONDS

Differenzen

  • UTCL_SECONDS_BETWEEN
  • TSTMP_SECONDS_BETWEEN
  • DATS_DAYS_BETWEEN
  • DATN_DAYS_BETWEEN

Aktueller Zeitpunkt 

  • UTCL_CURRENT
  • TSTMP_CURRENT_UTCTIMESTAMP
  • ABAP_SYSTEM_TIMEZONE
  • ABAP_USER_TIMEZONE

Parameter

Für einen CDS ABAP View können Parameter definiert werden, die dann als Ausdruck verwendet werden, z.B. zum Rechnen, als Vergleichswert oder als Funktionsparameter.

Default-Werte funktionieren nur in manchen Frameworks:

  • @Consumption.defaultValue – Konstanter Wert
  • @Environment.systemField Session-Variablen, z.B. Systemdatum
@AbapCatalog.sqlViewName: 'ZSQL_DEMO_PARA'
@EndUserText.label: 'Parameter in CDS Views'
DEFINE VIEW zjb_demo_parameter
    WITH PARAMETERS 
    @Consumption.defaultValue: '16'
    iv_vat : abap.int1 ,
    @Environment.systemField:  #SYSTEM_DATE
    iv_date: abap.dats
AS SELECT /bic/aorda001_12 
{
     KEY doc_number,
     net_value * division($parameters.iv_vat , 
                          100,
                          3 ) AS my_tax_value
} WHERE createdon = $parameters.iv_date

CDS Extraktoren

Delta Extraktion mit Zeitstempelfeld

Wie beim generischen Delta kann über ein Zeitstempelfeld ein Delta gebildet werden. Optional kann noch ein Sicherheitsintervall mitgegeben werden. 

@Analytics:{ dataCategory: #FACT, 
                        // #DIMENSION, #CUBE
             dataExtraction:{
                 enabled: true,
                 delta.byElement: {   
                    name:'upd_date', 
                    maxDelayinSeconds: 1800,
                    detectDeletedRecords: false,
                    ignoreDeletionAfterDays : '365'
} } }

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

CDS Table Functions sind in SQLScript programmierte Views. Sie basieren auf einer AMDP-Funktion, die durch ein CDS ABAP Objekt gekapselt wird.

CDS ABAP Tabellenfunktion

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.

CDS InfoProvider Views

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

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 _material 
           ON $projection.material = _material.material
{
...
  @ObjectModel.foreignKey.association: '_material'
  material,
...

CDS Dimension Views

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 [0..*] TO zjb_material_txt 
                          AS _material_text
           ON dim.material = _material_text.material
{
  @ObjectModel.text.association: '_material_text'
  KEY material,        
...

CDS Text Views

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 
}

CDS Query Views

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. 

Annotationen auf Viewebene

@Analytics.query: true
@Analytics.settings.zeroValues: { 
          handling:   #HIDE_IF_ALL,// #HIDE, #SHOW       
          hideOnAxis: #ROWS_COLUMNS// #COLUMNS, #ROWS }

Annotationen auf Feldebene

Filter mit Prompt

@Consumption.filter:{
   selectionType: #RANGE, // #INTERVAL,
                          // #SINGLE, #HIERARCHY_NODE 
   multipleSelections: false, 
   mandatory: true, 
   hidden: false, //Default:false 
   defaultValue: '0000000000011675' }

AnalyticDetails für Merkmale

@AnalyticsDetails.query:{
        display:       #KEY, //#KEY_TEXT, #TEXT
        axis:          #ROWS, //#COLUMNS
        totals:        #HIDE, //#SHOW
        hidden:        false, //Default: false
        sortDirection: #ASC //#DESC }

AnalyticDetails für Kennzahlen

@AnalyticsDetails.query:{ decimals: 0 ,
                          hidden:   false
                          formula:  ' a - b '  }
    1 AS a_minus_b,

@EndUserText.label: 'Anzahl Belege' 
@AnalyticsDetails.exceptionAggregationSteps: 
   [{ exceptionAggregationBehavior: #COUNT, 
      exceptionAggregationElements: ['doc_number'] }] 
   1 AS doc_count