Wir zeigen stets zu unserem Vorschlag in modernem ABAP eine Variante, wie das in klassischem ABAP aussehen könnte. Die Beispiele sollen 100% identische Ergebnisse produzieren. Es kann gut sein, dass es für das eine oder andere Beispiel auch elegantere Varianten gibt.
Die Formatierung des Quellcode ist teilweise nicht optimal, weil wir auf Grund des Spaltenlayouts nicht viel Platz haben. Darum sind häufig mehr Zeilenumbrüche im Code enthalten, als man das sonst machen würde.
Unter der Linie sind Referenzen, hauptsächlich natürlich auf die Dokumentation der SAP und interessante Blogs.
Die Sprache ABAP ist laut Wikipedia aus dem Jahre 1983. Seit dem hat sich eine Menge verändert. Die letzte große Evolutionsstufe hat mit dem SAP NetWeaver 7.40 begonnen, als die Erweiterungen für die Next Generation ABAP Plattform (NGAP, ABAP 8) von der SAP nach 7.40 portiert wurden. Leider wurde das Projekt NGAP gestoppt, aber vieles von den ABAP Erweiterungen ist erhalten geblieben.
Mit dem modernen ABAP werden vor allem zwei Ziele verfolgt:
Ersteres motiviert vor allem die Änderungen im ABAP SQL wo hingegen der zweite Punkt sich in erster Linie bedeutet, dass man sich viele Hilfsvariablen sparen kann. Damit wird der Code schlanker und von unnötigen Anweisungen befreit, die eigentlich nichts zum Erzeugen des Ergebnis beitragen.
Mit Inline Deklarationen kann eine Variable dort definiert werden, wo Sie das erste Mal vewendet wird - also dort wo ihr das erste Mal ein Wert zugewiesen wird. An vielen Stellen im ABAP Code ergibt sich dort der Datentyp einer Variablen aus dem Kontext.
Mit DATA(<variablenname>)
kann man an Ort und Stelle eine Variable definieren, wo man sie braucht.
SELECT *
FROM zbc_users
INTO TABLE @DATA(Result).
DATA Result
TYPE TABLE OF zbc_users.
SELECT *
FROM zbc_users
INTO TABLE Result.
Vorteile der Inline Deklaration sind, neben dem kompakteren Code, ausserdem noch die Flexibilität. Wenn in dem Beispiel sich die Feldliste verändert, wird der Datentyp von RESULT
automatisch angepasst. Gerade bei JOIN Operationen hat man häufig auch keine passende Strutkurdefinition.
LOOP AT Result
INTO DATA(ResultLine).
...
ENDLOOP.
DATA ResultLine
LIKE LINE OF Result.
LOOP AT Result
INTO ResultLine.
...
ENDLOOP.
Auch Feldsymbole können mit Inline-Deklaration einem existierenden Speicherbereich zugewiesen werden. Entweder mit einem ASSIGN
oder mit dem den passenden Anweisungen für den Zugriff auf interne Tabellen wie zum Beispiel
LOOP AT ... ASSIGNING FIELD-SYMOBL(<fs-name>).
oder
READ TABLE ... ASSIGNING FIELD-SYMBOL(<fs-name>) ...
&&
Zwei Zeichenketten können mit dem Operator &&
verkettet werden. Das ist viel eleganter als mit CONCATENATE
und funktioniert auch an Operanden-Positionen ohne Hilfsvariable.
out->write( `Es ist das Jahr `
&& sy-datum(4) ).
DATA tmp TYPE c LENGTH 4.
CONCATENATE `Es ist das Jahr `
sy-datum(4)
INTO tmp.
out->write( tmp ).
Beim Zusammenbauen von Zeichenketten benötigt man häufig das 'Anhängen'. Beispielsweise wenn man HTML generiert.
html &&= `<b>Hallo</b>`
CONCATENATE html
`<b>Hallo</b>`
INTO html.
String Templates sind Ausdrücke, die eine Zeichenkette erzeugen. Sie bestehen aus Literalen, die eingebettete Ausdrücke, Formatierung und Steuerzeichen enthalten können. Ein String-Template beginnt und endet mit einem senkrechten Strich |
. Alles dazwischen ist konstanter Text (=Literal), ausser er ist ein von geschweiften Klammern { ... }
umgebener, eingebetter Ausdruck.
Die Zeichen {
, }
, |
und \
müssen im Literal durch ein Backslash \
escaped werden.
out->write( |Heute: {
sy-datum DATE = USER }| ).
DATA tmp TYPE string.
DATA datum TYPE c LENGTH 10.
WRITE sy-datum TO datum.
CONCATENATE `Heute: `
datum
INTO tmp.
out->write( tmp ).
Die Steuerzeichen
\n
- Zeilenvorschub/Line Feed \r
- Wagenrücklauf/Return und \t
- Tabulator können direkt in String Templates verwendet werden. Damit können also ohne weiteres auch mehrzeilige Texte ohne die Verwendung von CL_ABAP_CHAR_UTILS=>CR_LF
erzeugt werden.
out->write(
|Hallo\r\nWelt| ).
DATA tmp TYPE string.
CONCATENATE `Hallo`
cl_abap_char_utilities=>cr_lf
`Welt`
INTO tmp.
out->write( tmp ).
Hinter dem sperrigen Begriff Prädikative Methodenaufruf steckt ein einfaches Konzept, das in (fast) allen anderen Programmiersprachen Standard ist: Ein Methodenaufruf als Prädikat, beispielsweise direkt in einer IF
Anweisung.
REDUCE
Wert aus Tabellen berechnenCORRESPONDING
und FILTER
SAP Dokumentation FILTER
und CORRESPONDING
Auch wenn der Name anderes erwarten lässt, so liefern uns Tabellenausdrücke Zeilen einer Tabelle. In SQL würde man sie deshalb Zeilenausdrücke nennen.
Es handelt sich nicht um Kopien der Zeile sondern um die Zeile in der Tabelle. Darum verändern Schreib-Operationen auch die Tabelle. Sie ersetzen somit READ ... INTO
und READ ... ASSIGNING
Anweisungen.
Struktur von Tabellenausdrücken
<Tabelle>[ <Zeilenspezifikation> ]
Die Tabelle kann dabei eine beliebige interne Tabelle sein. Die Zeilenspezifikation erfolgt in eckigen Klammern und kann auf unterschiedliche Art stattfinden:
* Kopie der ersten Zeile
DATA(row) = users[ 1 ].
* Ändern des Vornamens 1. Zeile
users[ 1 ]-firstname = 'Edgar'.
* Ändern von Peters Nachname
users[ firstname = 'Peter'
]-lastname ='Pan'.
* Kopie der ersten Zeile
DATA row LIKE LINE OF users.
READ TABLE users INTO row INDEX 1.
* Ändern des Vornamens 1. Zeile
FIELD-SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row> INDEX 1.
<row>-firstname = 'Edgar'.
* Ändern von Peters Nachname
FIELD-SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row>
WITH firstname = 'Peter'.
<row>-lastname = 'Pan'.
Fehlerverarbeitung in Tabellenausdrücken
Ein Zugriff auf nicht existierende Zeilen erzeugt eine abfangbare Ausnahme vom Typ CX_SY_ITAB_LINE_NOT_FOUND
.
* Ändern von Peters Nachname
TRY.
users[ firstname = 'Peter'
]-lastname ='Pan'.
CATCH CX_SY_ITAB_LINE_NOT_FOUND.
ENDTRY.
* Ändern von Peters Nachname
FIELD-SYMBOLS <row> LIKE LINE OF users.
READ TABLE users ASSIGNING <row>
WITH firstname = 'Peter'.
IF sy-subrc = 0.
<row>-lastname = 'Pan'.
ENDIF.
Bei lesendem Zugriff kann alternativ auch mit dem VALUE
-Operator ein Defaultwert erzeugt werden oder der Zugriff als OPTIONAL
markiert werden.
...VALUE #( <Tabelle>[<Zeilenspezifikation>]
DEFAULT <Alternativer Tabellenausdruck> | OPTIONAL )
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