Modernes ABAP

Neue ABAP SQL Syntax

(C) Brandeis Consulting.

Ziel der neuen ABAP SQL Syntax

  • Erweiterung des SQL-Funktionsumfangs um Standard SQL-Features
  • Nutzung der speziellen SAP HANA Features in ABAP
(C) Brandeis Consulting.

Wichtigste Änderungen in der Syntax

Damit ABAP SQL erweitert werden konnte, mussten zwei Dinge an den Standard angepasst werden.

Kommas in der Feldliste

Nach jedem Spaltennamen kommt jetzt ein Komma. Das war früher nicht notwendig, da keine Ausdrücke in der Feldliste erlaubt waren. Damit war stets klar, was eine Spalte ist. Jetzt brauchen wir ein Trennzeichen:

Escaping von Hostvariablen mit @

Da bislang die Hostvariablen (= ABAP Variablen) nur an fest definierten Stellen stehen konnten, war das nicht notwendig. Jetzt kann man sie fast überall als Ausdruck verwenden.

INTO / APPENDING kommt am Schluss

Damit auch ein UNION in ABAP SQL möglich ist, muss die INTO Klausel als letztes, nach den einzelnen SELECT erfolgen.

(C) Brandeis Consulting.

Wichtigste Features mit der neuen Syntax

  • Ausdrücke in der Feldliste
  • Window Functions (ab 7.54)
  • Interne Tabellen in der FROM Klausel
  • Common Table Expressions mit WITH (ab 7.51)
  • UNION
  • Pfadausdrücke
  • Neue Möglichkeiten von JOIN
(C) Brandeis Consulting.

Ausdrücke in der Feldliste

In der Feldliste können nicht nur Felder aus den Quelltabellen auftauchen. Ebenfalls erlaubt sind die folgenden Ausdrücke:

  • SQL-Funktionen
  • Operatorausdrücke, also Berechnungen und Verkettungen mit +, -, *, / und &&
  • Typkonvertierungen mit CAST
  • CASE Ausdrücke
  • Window Functions
(C) Brandeis Consulting.

Ausdrücke in der Feldliste

In der Feldliste können nicht nur Felder aus den Quelltabellen auftauchen. Ebenfalls erlaubt sind die folgenden Ausdrücke:

  • SQL-Funktionen
  • Operatorausdrücke mit +, -, *, / und &&
  • Typkonvertierungen mit CAST
  • CASE Ausdrücke
  • Window Functions
(C) Brandeis Consulting.

SQL-Funktionen

Es kommen mit jedem Release mehr hinzu! Mit 7.50 ist das noch sehr begrenzt. ;-(

  • Datentyp spezifische
    • Zeichenketten
    • Datum und Zeit
    • Numerische Daten
  • Konvertierung zwischen den Datentypen

SQL-Funktionen von CDS ABAP und ABAP SQL sind weitgehend identisch. Im Zweifel muss man einen Blick in die Referenzdokumentation werfen.

(C) Brandeis Consulting.

SQL-Funktionen für Zeichenketten

Die übliche Verdächtigen...

SQL-Funktion Argument 1 Argument 2 Argument 3
CONCAT Zeichenkette 1 Zeichenkette 2
CONCAT_WITH_SPACE Zeichenkette 1 Zeichenkette 2 # Spaces
LENGTH Zeichenkette
LEFT Zeichenkette Länge
RIGHT Zeichenkette Länge
SUBSTRING Zeichenkette 1.Zeichen Länge
LOWER Zeichenkette
UPPER Zeichenkette
INSTR Zeichenkette Suchstring
REPLACE Zeichenkette Suchstring Ersatz
LPAD Zeichenkette Länge Muster
RPAD Zeichenkette Länge Muster
LTRIM Zeichenkette Zeichen
RTRIM Zeichenkette Zeichen
(C) Brandeis Consulting.

SQL-Funktionen für numerische Werte

Neben den üblichen arithmetischen Operatoren +, -, * und /

Kategorie SQL-Funktion Argument 1 Argument 2 Argument 3 Ergebnis
Vorzeichen ABS Wert Betrag des Wert
Division DIV Zähler Nenner Ganzzahl
DIVISION Zähler Nenner Dezimalstellen Dezimalzahl
MOD Zähler Nenner Divisionsrest
Runden ROUND Wert NK-Stellen Wert gerundet
CEIL Wert Ganzzahl
FLOOR Wert Ganzzahl
Umrechnungen CURRENCY_CONVERSION
(C) Brandeis Consulting.

SQL-Funktionen für Datum und Zeit

Bei vielen SQL-Funktionen muss ein Fehlerverhalten (<on_error>) mit angegeben. Die möglichen Werte stehen in den jeweils passenden globalen ABAP-Klassen als Enumneration zur Verfügung. Hier wird beispielhaft die Klassen SQL_TSTMPL_TO_UTCL verwendet:

  • SQL_TSTMPL_TO_UTCL=>C_ON_ERROR-FAIL
  • SQL_TSTMPL_TO_UTCL=>C_ON_ERROR-SET_TO_NULL
  • SQL_TSTMPL_TO_UTCL=>C_ON_ERROR-SET_TO_INITIAL

Falls der Quellwert bei Konvertierungen initial ist, kann auch hier das Verhalten vorgegeben werden:

  • SQL_TSTMPL_FROM_UTCL=>C_ON_INITIAL-FAIL
  • SQL_TSTMPL_FROM_UTCL=>C_ON_INITIAL-SET_TO_NULL
  • SQL_TSTMPL_FROM_UTCL=>C_ON_INITIAL-SET_TO_INITIAL
(C) Brandeis Consulting.

SQL-Funktionen für die Zeitberechnung

Kategorie SQL-Funktion Argument 1 Argument 2 Argument 3 Argument 4 Argument 5
Addition von Zeit DATS_ADD_DAYS Datum #Tage
DATS_ADD_MONTHS Datum #Monate
TSTMP_ADD_SECONDS Zeitstempel #Sekunden
Differenzen DATS_DAYS_BETWEEN Datum Datum
TSTMP_SECONDS_BETWEEN Zeitstempel Zeitstempel
Gültigkeit DATE_IS_VALID Datum
TIMS_IS_VALID Uhrzeit
TSTMP_IS_VALID Zeitstempel
Konvertierung DATS_TIMS_TO_TSTMP Datum Uhrzeit Zeitzone Mandant OnError
TSTMP_TO_DATS Zeitstempel Zeitzone Mandant OnError
TSTMP_TO_TIMS Zeitstempel Zeitzone Mandant OnError
Zeitzonen ABAP_SYSTEM_TIMEZONE Mandant OnError
ABAP_USER_TIMEZONE User Mandant OnError
(C) Brandeis Consulting.

Ausdrücke in der Feldliste

In der Feldliste können nicht nur Felder aus den Quelltabellen auftauchen. Ebenfalls erlaubt sind die folgenden Ausdrücke:

  • SQL-Funktionen
  • Operatorausdrücke mit +, -, *, / und &&
  • Typkonvertierungen mit CAST
  • CASE Ausdrücke
  • Window Functions
(C) Brandeis Consulting.

Operatorausdrücke

Berechnungen

Berechnungen sind mit +, - und * wie gewohnt möglich. Die Division mit dem / Operator ist nur mit Float Datentypen erlaubt. Statt dessen sollte die SQL-Funktion DIVISION(Zaehler, Nenner, #NK-Stellen) verwendet werden.

Verkettung von Zeichenketten

Mit dem && Operator können zwei Zeichenketten verkettet werden.

(C) Brandeis Consulting.

Ausdrücke in der Feldliste

In der Feldliste können nicht nur Felder aus den Quelltabellen auftauchen. Ebenfalls erlaubt sind die folgenden Ausdrücke:

  • SQL-Funktionen
  • Operatorausdrücke mit +, -, *, / und &&
  • Typkonvertierungen mit CAST
  • CASE Ausdrücke
  • Window Functions
(C) Brandeis Consulting.

Typkonvertierung mit CAST

An unterschiedlichen Stellen ist eine Typkonvertierung erforderlich, z.B. wenn ein festgelegter Datentyp vorgegeben wird.

  • CAST (<Wert> AS <Datentyp> )

Der Wert kann ein beliebiger Ausdruck sein. Als Datentyp kommt in Frage:

  • Ein Datenelement
  • Ein eingebauter ABAP Datentyp mittels abap.<datentyp>
(C) Brandeis Consulting.

Ausdrücke in der Feldliste

In der Feldliste können nicht nur Felder aus den Quelltabellen auftauchen. Ebenfalls erlaubt sind die folgenden Ausdrücke:

  • SQL-Funktionen
  • Operatorausdrücke mit +, -, *, / und &&
  • Typkonvertierungen mit CAST
  • CASE Ausdrücke
  • Window Functions
(C) Brandeis Consulting.

CASE Ausdrücke - Einfach

Der CASE Ausdruck liefert genau einen Wert:

CASE Wert
        WHEN Vergleichswert1 THEN Ergebniswert1
        WHEN Vergleichswert2 THEN Ergebniswert2
        ...
        ELSE AlternativWert
    END

Überall wo hier Wert steht, kann ein beliebiger Ausdruck sein…

(C) Brandeis Consulting.

CASE WHEN Ausdrücke - Komplex

Auch Searched Case oder CASE WHEN genannt

 CASE   WHEN Bedingung1 THEN Ergebniswert1
        WHEN Bedingung2 THEN Ergebniswert2
        ...
        ELSE AlternativWert
    END

Die Bedingungen können sich auf unterschiedliche Spalten und Ausdrücke beziehen. Wenn mehr als eine Bedingung nach TRUE ausgewertet wird, so wird der erste Ergebniswert zurückgegeben.

(C) Brandeis Consulting.

Assoziationen

select from I_SalesDocument
   FIELDS
     SalesDocument,
     \_item[ (1) inner where  SalesDocumentItem = '000010' ]-SalesDocumentItem,
     \_item[ (1) inner where  SalesDocumentItem = '000010' ]-Material,
     \_item[ (1) inner where  SalesDocumentItem = '000010' ]\_Material-MaterialBaseUnit,
     \_item[ (1) inner where  SalesDocumentItem = '000010' ]\_material\_Text[  (1) inner where Language = @sy-langu ]-MaterialName
     into table @data(result).

     out->write( result ).
  ENDMETHOD.
(C) Brandeis Consulting.

Window Functions (seit 7.54)

Window Functions berechnen Daten ähnlich wie Aggregationen, d.h. über mehrere Zeilen hinweg. Dabei wird aber die Granularität der Daten nicht verändert.

(C) Brandeis Consulting.

Struktur von Window Functions - Partitionen

SELECT location,
    ldate,
    value,
    SUM( value ) OVER( PARTITION BY location ) 
                                      AS lsum
FROM zbc_wf
ORDER BY location,
        ldate

Mit der PARTITION BY-Klausel werden die Daten in mehrere Partitionen aufgeteilt. Diese Aufteilung kann auf der Grundlage einer oder mehrerer Spalten vorgenommen werden. Oder durch die Verwendung von Ausdrücken. Im Beispiel berechnet sie die Summe von der Spalte VALUE innerhalb der Partitionen.

LOCATION LDATE VALUE LSUM
A 10.10.2022 5.0 22.0
A 11.10.2022 3.0 22.0
A 12.10.2022 8.0 22.0
A 13.10.2022 6.0 22.0
B 10.10.2022 7.0 16.0
B 11.10.2022 8.0 16.0
B 12.10.2022 1.0 16.0
C 10.10.2022 13.0 30.0
C 11.10.2022 3.0 30.0
C 12.10.2022 8.0 30.0
C 13.10.2022 4.0 30.0
C 14.10.2022 2.0 30.0
(C) Brandeis Consulting.

Struktur von Window Functions - ORDER BY

    SELECT location,
        ldate,
        value,
        SUM( value ) OVER( PARTITION BY location
                            ORDER BY ldate ) AS lsum
    FROM zbc_wf
    ORDER BY location,
            ldate
    INTO TABLE @DATA(result)

Einige Window-Functions benötigen eine bestimmte Reihenfolge der Daten innerhalb der Partition. Z.B. ROW_NUMBER, LEAD oder LAG.

Das Verhalten der Aggregat Funktionen ändert sich, wenn eine ORDER BY Klausel angegeben wird. Sie berücksichtigt nur die aktuelle Zeile plus alle Zeilen davor in dieser Partition

LOCATION LDATE VALUE LSUM
A 10.10.2022 5.0 5.0
A 11.10.2022 3.0 8.0
A 12.10.2022 8.0 16.0
A 13.10.2022 6.0 22.0
B 10.10.2022 7.0 7.0
B 11.10.2022 8.0 15.0
B 12.10.2022 1.0 16.0
C 10.10.2022 13.0 13.0
C 11.10.2022 3.0 16.0
C 12.10.2022 8.0 24.0
C 13.10.2022 4.0 28.0
C 14.10.2022 2.0 30.0
(C) Brandeis Consulting.

Struktur von Window Functions - ROWS

SELECT location,
        ldate,
        value,
        SUM( value ) OVER( PARTITION BY location
                               ORDER BY ldate
                           ROWS BETWEEN 1 PRECEDING 
                                    AND 1 FOLLOWING )
                                              AS lsum
    FROM zbc_wf
    ORDER BY location,
            ldate
    INTO TABLE @DATA(result).

Mit ROWS BETWEEN <start> AND <end> werden die bei der Berechnung zu verwendenden Zeilen konkret benannt. Möglich sind hier zum Beispiel:

  • X PRECEDING oder UNBOUND PRECEDING
  • X FOLLOWING oder UNBOUND FOLLOWING
  • CURRENT ROW
LOCATION LDATE VALUE LSUM
A 10.10.2022 5.0 8.0
A 11.10.2022 3.0 16.0
A 12.10.2022 8.0 17.0
A 13.10.2022 6.0 14.0
B 10.10.2022 7.0 15.0
B 11.10.2022 8.0 16.0
B 12.10.2022 1.0 9.0
C 10.10.2022 13.0 16.0
C 11.10.2022 3.0 24.0
C 12.10.2022 8.0 15.0
C 13.10.2022 4.0 14.0
C 14.10.2022 2.0 6.0
(C) Brandeis Consulting.

Window Functions - Die Funktionen

Aggregatfunktionen

Berechnungen

  • SUM( )
  • AVG( )
  • COUNT( )
  • VAR( )

Einzelwerte

  • MEDIAN( )
  • NTH_VALUE( )
  • MIN( )
  • MAX( )
  • FIRST_VALUE( )
  • LAST_VALUE( )

Nummerierung und Gruppierung

In Bezug auf die Sortierung

  • DENSE_RANK( )
  • RANK( )
  • ROW_NUMBER( )

Zufällige Verteilung in Gruppen

  • RANDOM_PARTITION( )
  • BINNING( )
  • NTILE( )
(C) Brandeis Consulting.

Window Functions - Zeilenübergreifender Zugriff

Mit LEAD() und LAG() kann man auf Daten einer anderen Zeile vor oder nach der aktuellen Zeile zugreifen. Damit kann man beispielsweise direkt die Differenz zum Vorgänger ermitteln.

Syntax

LAG(<expression>[,<offset>])
LEAD(<expression>[,<offset>])
(C) Brandeis Consulting.

Window Functions - Beispiel für LEAD( )

    SELECT assignee,
           task_id,
           due_date,
           days_between( due_date
                        ,LEAD( due_date )
                           OVER( PARTITION BY assignee
                                 ORDER BY due_date )
                        ) AS ddd
      FROM zbc_tasks
      ORDER BY assignee,
               due_date
     INTO TABLE @DATA(result).
ASSIGNEE TASK_ID DUE_DATE DDD
000001 000998 2021-10-05 7
000001 000892 2021-10-12 48
000001 000383 2021-11-29 6
000001 000225 2021-12-05 1
000001 000239 2021-12-06 18
000001 000425 2021-12-24 105
000001 000472 2022-04-08 12
000001 000149 2022-04-20 49
000001 000493 2022-06-08 67
000001 000129 2022-08-14 20
000001 000629 2022-09-03 22
000001 000697 2022-09-25 4
000001 000435 2022-09-29 2
000001 000271 2022-10-01 65
(C) Brandeis Consulting.

Common Table Expressions (CTE) mit WITH (ab 7.51)

Die Idee der CTEs ist, dass man die Verschachtelung von/in SELECT Abfragen reduziert, in dem man Tabellenausdrücke vorab definiert.

WITH +<CTE_X> AS (SELECT ...FROM <Tabelle_A>)

SELECT ... 
 FROM <Tabelle_B>
 INNER JOIN +<CTE_X> 
 INTO TABLE ...    .

Das entspricht eigentlich der Definition eines Views bzw. einer Tabellenvariable im SQLScript.

Der große Vorteil gegenüber einer internen Tabelle, die dann mit in den SELECT eingebunden wird, ist, dass die gesamte Abfrage von der HANA Datenbank verarbeitet wird. Das ist normalerweise erheblich schneller.

(C) Brandeis Consulting.

CTE Beispiel

Für jeden Benutzer werden die Aufgaben in der CTE +CNT gezählt. Das Ergebnis wird dann dazu gejoint.

    WITH +cnt AS ( SELECT assignee ,
                          COUNT( * ) AS task_cnt
                     FROM zbc_tasks
                     GROUP BY assignee )
    SELECT  ltrim( task_id, '0' ) AS task_id,
            task_key,
            left( summary, 10 ) AS summary,
            status,
            t~assignee,
            c~task_cnt,
            due_date,
            product
      FROM zbc_tasks AS t
      INNER JOIN +cnt AS c
      ON t~assignee = c~assignee
      ORDER BY t~assignee

      INTO TABLE @DATA(result).
(C) Brandeis Consulting.

UNION

    SELECT task_id
      FROM zbc_tasks WHERE task_id < '0000000005'

      UNION ALL

    SELECT CAST( '0000000001' AS NUMC( 10 ) ) AS task_id
      FROM zbc_wf

    INTO TABLE @DATA(result).
(C) Brandeis Consulting.

JOIN mit internen Tabellen

SAP Dokumentation

(C) Brandeis Consulting.

Alle Join Arten incl. CROSS JOIN

... [(] { data_source [AS tabalias]}|join
          {[INNER] JOIN}|{LEFT|RIGHT [OUTER [MANY TO ONE]] JOIN}|{CROSS JOIN}
             { data_source [AS tabalias]}|join [ON sql_cond] [)] ... .

Beachte: Kardinalitäten N:1 können angegeben werden

(C) Brandeis Consulting.

Clean Code Empfehlungen

  • Saubere Formatierung mit Einrückung und Zeilenumbrüchen:
    CASE WHEN due_date > @sy-datum
            THEN division( 10
                            , abs( days_between( @sy-datum
                                                , due_date ) )
                            , 4 ) * priority
            ELSE priority END 
                                    AS weighted_priority,
(C) Brandeis Consulting.