Modern ABAP

New ABAP SQL Syntax

(C) Brandeis Consulting

Goal of the New ABAP SQL Syntax

  • Extend SQL functionality with standard SQL features
  • Enable the use of special SAP HANA features in ABAP
(C) Brandeis Consulting

Key Changes in the Syntax

To extend ABAP SQL, two fundamental adjustments to the standard were necessary.

Commas in the Field List

Now, every column name must be followed by a comma.
Previously, this wasn’t required since expressions weren’t allowed in the field list —
so it was always clear what was a field.
Now we need a delimiter:

Escaping Host Variables with @

Until now, host variables (= ABAP variables) could only appear in certain predefined places,
so escaping wasn’t needed.
Now they can be used almost anywhere in expressions.

INTO / APPENDING Comes at the End

To allow UNION operations in ABAP SQL,
the INTO clause must appear last — after all individual SELECT statements.

(C) Brandeis Consulting

Main Features of the New Syntax

  • Expressions in the field list
  • Window functions (since 7.54)
  • Internal tables in the FROM clause
  • Common Table Expressions (CTE) using WITH (since 7.51)
  • UNION
  • Path expressions
  • New JOIN capabilities
(C) Brandeis Consulting

Expressions in the Field List

The field list can now contain more than just columns from source tables.
The following expressions are also allowed:

  • SQL functions
  • Operator expressions such as calculations or concatenations using +, -, *, /, and &&
  • Type conversions using CAST
  • CASE expressions
  • Window functions
(C) Brandeis Consulting

SQL Functions

More are added with every release!
With 7.50 the set is still quite limited. ;-(

  • Data type–specific functions
    • String
    • Date and time
    • Numeric
  • Conversion between data types

SQL functions in CDS ABAP and ABAP SQL are largely identical.
When in doubt, check the reference documentation.

(C) Brandeis Consulting

SQL Functions for Strings

The usual suspects...

SQL Function Argument 1 Argument 2 Argument 3
CONCAT String 1 String 2
CONCAT_WITH_SPACE String 1 String 2 #Spaces
LENGTH String
LEFT String Length
RIGHT String Length
SUBSTRING String Start position Length
LOWER String
UPPER String
INSTR String Search string
REPLACE String Search string Replacement
LPAD String Length Pattern
RPAD String Length Pattern
LTRIM String Character
RTRIM String Character
(C) Brandeis Consulting

SQL Functions for Numeric Values

In addition to the usual arithmetic operators +, -, *, and /:

Category SQL Function Arg 1 Arg 2 Arg 3 Result
Sign ABS Value Absolute value
Division DIV Numerator Denominator Integer
DIVISION Numerator Denominator Decimals Decimal
MOD Numerator Denominator Remainder
Rounding ROUND Value Decimals Rounded value
CEIL Value Integer
FLOOR Value Integer
Conversion CURRENCY_CONVERSION
(C) Brandeis Consulting

SQL Functions for Date and Time

Many SQL functions require an error handling behavior (<on_error>).
Possible values are defined in the respective global ABAP classes as enumerations, e.g. class SQL_TSTMPL_TO_UTCL:

  • 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

If the source value in conversions is initial, the behavior can also be specified:

  • 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 Functions for Time Calculations

Category SQL Function Arg 1 Arg 2 Arg 3 Arg 4 Arg 5
Time addition DATS_ADD_DAYS Date #Days
DATS_ADD_MONTHS Date #Months
TSTMP_ADD_SECONDS Timestamp #Seconds
Differences DATS_DAYS_BETWEEN Date Date
TSTMP_SECONDS_BETWEEN Timestamp Timestamp
Validity DATS_IS_VALID Date
TIMS_IS_VALID Time
TSTMP_IS_VALID Timestamp
Conversion DATS_TIMS_TO_TSTMP Date Time Timezone Client OnError
TSTMP_TO_DATS Timestamp Timezone Client OnError
TSTMP_TO_TIMS Timestamp Timezone Client OnError
Time zones ABAP_SYSTEM_TIMEZONE Client OnError
ABAP_USER_TIMEZONE User Client OnError
(C) Brandeis Consulting

Operator Expressions

Calculations

Calculations using +, -, and * work as usual.
Division with / is allowed only for float data types.
Instead, use the SQL function DIVISION(numerator, denominator, #decimals).

String Concatenation

Strings can be concatenated using the && operator.

(C) Brandeis Consulting

Type Conversion with CAST

Type conversion is needed in various places, e.g. when a specific data type must be enforced.

  • CAST(<value> AS <datatype>)

The value can be any expression. Valid datatypes are:

  • A data element
  • A built-in ABAP type via abap.<datatype>
(C) Brandeis Consulting

CASE Expressions – Simple

The CASE expression returns exactly one value:

CASE value
      WHEN compare_value1 THEN result_value1
      WHEN compare_value2 THEN result_value2
      ...
      ELSE alternative_value
END

Every occurrence of “value” can be any valid expression.

(C) Brandeis Consulting

CASE WHEN Expressions – Complex

Also known as a searched CASE expression or CASE WHEN.

CASE WHEN condition1 THEN result_value1
     WHEN condition2 THEN result_value2
     ...
     ELSE alternative_value
END

Conditions can refer to different columns or expressions.
If more than one condition evaluates to TRUE, the first matching result is returned.

(C) Brandeis Consulting

Associations

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 (since 7.54)

Window functions perform calculations similar to aggregations,
i.e. across multiple rows — but without changing the data’s granularity.

(C) Brandeis Consulting

Structure of Window Functions – PARTITION

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

The PARTITION BY clause divides data into partitions based on one or more columns or expressions.
In this example, it calculates the sum of VALUE within each partition.

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

Structure of 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)

Some window functions require an order within the partition —
e.g. ROW_NUMBER, LEAD, or LAG.

When an ORDER BY clause is specified,
aggregates only consider the current row and all previous rows in that 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

Structure of 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).

The ROWS BETWEEN <start> AND <end> clause explicitly defines
which rows are included in the calculation.
Possible values include:

  • X PRECEDING or UNBOUND PRECEDING
  • X FOLLOWING or 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 – Available Functions

Aggregate Functions

Calculations

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

Single Values

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

Numbering and Grouping

Based on Ordering

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

Random Distribution into Groups

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

Window Functions – Accessing Other Rows

With LEAD() and LAG() you can access data from rows before or after the current one —
for example, to calculate differences from the previous row.

Syntax

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

Example of 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) with WITH (since 7.51)

The idea of CTEs is to reduce nested SELECT statements
by defining table expressions beforehand.

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

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

This is conceptually similar to defining a VIEW or a table variable in SQLScript.

The major advantage compared to using an internal table in a SELECT is that
the entire query is processed by the HANA database — usually much faster.

(C) Brandeis Consulting

CTE Example

For each user, the number of tasks is counted in the CTE +CNT.
The result is then joined to the main query.

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).


# UNION

```abap
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 with Internal Tables

SAP Documentation

(C) Brandeis Consulting

All Join Types Including 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] [)] ...

Note: cardinalities such as N:1 can be specified.

(C) Brandeis Consulting

Clean Code Recommendations

  • Clean formatting with indentation and line breaks:
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