Skip to content

Lesson 1 — Database Basics, ABAP SQL, and Code Organization

Until now, you have been working with ABAP syntax and object-oriented programming.

In this lesson, you will connect that knowledge to persistent data.

You will learn this small architecture:

text
Database Table

   ABAP SQL

 Reader Class

 Runner Class

    Console

The goal is not only to make a SELECT work. The goal is also to give classes clear responsibilities.

Scope

This lesson covers read access with SELECT, together with code organization for database access.

Table creation, INSERT, UPDATE, DELETE, and RAP business services are outside the scope of this lesson.

Lesson information

DurationAbout 90–120 minutes
EnvironmentSAP BTP ABAP Trial
ToolingEclipse + ADT
PrerequisitesABAP syntax and OOP
Demo table/DMO/CARRIER
OutputABAP Console

Learning objectives

After this lesson, you should be able to:

  • explain persistent database data;
  • distinguish a database table from an ABAP internal table;
  • inspect a database table in ADT and use Data Preview;
  • open and use the ADT SQL Console to explore an ABAP SQL query;
  • explain where ABAP code executes and why ordinary ABAP SQL needs no JDBC/ODBC-style connection string;
  • use SELECT, FIELDS, WHERE, ORDER BY, host variables, and SELECT SINGLE;
  • define a small result structure and internal-table type;
  • create a Reader class responsible for data access;
  • create a Runner class responsible for execution and console output;
  • call Reader methods from the Runner;
  • explain why this Reader is not a RAP business service.

Replace ###

Use your own student/group suffix:

text
ZCL_CARRIER_READER_###  → ZCL_CARRIER_READER_017
ZCL_SQL_L01_###         → ZCL_SQL_L01_017

ABAP Cloud mindset

The /DMO/* objects belong to SAP's ABAP Flight Reference Scenario and are demo/tutorial content.

In productive ABAP Cloud development, do not assume that every SAP repository object can be consumed directly. Released APIs and cloud-development contracts matter.

Do not create your own objects in the /DMO/ namespace.

1. Persistent data

An ABAP variable exists while your code runs:

abap
DATA name TYPE string.
name = 'Lufthansa'.

Business applications also need data that remains available independently of one execution. That is persistent data.

A database table stores persistent rows and columns. One or more key fields identify records.

2. Explore /DMO/CARRIER

Open:

text
/DMO/CARRIER

with:

text
Ctrl + Shift + A

Find these fields:

FieldMeaningKey?
carrier_idCarrier identifierYes
nameCarrier nameNo
currency_codeCurrency codeNo

Open Data Preview and write down one carrier ID and one currency code that actually exist in your system.

For supported table/view contexts, ADT also provides:

text
Alt + F8

3. Explore the query in SQL Console

Data Preview is useful when you want to inspect records. ADT also provides an SQL Console where you can write and execute ABAP SQL queries directly.

Open SQL Console in one of these ways:

  • from the Data Preview editor, choose the SQL Console tab;
  • right-click /DMO/CARRIER and choose Open With → SQL Console;
  • right-click the ABAP project and choose SQL Console.

When SQL Console is opened from Data Preview, ADT can carry over the current query from Data Preview.

Enter this query:

abap
SELECT FROM /dmo/carrier
  FIELDS carrier_id,
         name,
         currency_code
  ORDER BY carrier_id

Run the query.

SQL Console displays the query result and query statistics. It supports the modern ABAP SQL syntax used in this course.

Notice that the SQL Console query has no INTO TABLE.

The SQL Console itself displays the result. There is no ABAP program variable receiving it.

Later, the same query inside a Reader method will need an ABAP target:

abap
INTO TABLE @carriers

This gives us a useful distinction:

text
Data Preview
  → inspect existing data

SQL Console
  → write and execute a query interactively

Reader class
  → use the query as part of application code

TIP

Use SQL Console to inspect and experiment with ABAP SQL queries. Put application data-access logic in the classes and data-model objects that belong to the application.

4. Database table vs internal table

A database table is persistent:

text
/DMO/CARRIER

An ABAP internal table is an ABAP data object in program memory.

The flow is:

text
Database Table

      │ SELECT

ABAP Internal Table

They can both contain rows, but they live in different places and have different responsibilities.

5. Where is the database connection?

If you know Java, Python, C#, or Node.js, you may expect:

text
Application

Driver

Connection string / credentials

Database

Ordinary ABAP SQL in this lesson works differently.

Your class runs in the ABAP backend system, not locally inside Eclipse.

text
Your computer
Eclipse + ADT

ABAP Cloud Project

ABAP backend

Your ABAP code

ABAP SQL / database interface

standard database connection

system database

That is why this contains no hostname, driver, username, password, or connection string:

abap
SELECT FROM /dmo/carrier

TIP

ADT connects to the ABAP backend. Your ABAP code executes there, and the backend performs the database access.

WARNING

ABAP also supports advanced external-data and additional-connection scenarios. They are outside this lesson.

6. What is ABAP SQL?

ABAP provides ABAP SQL for reading SQL data sources.

Older material may call it Open SQL.

Example:

abap
SELECT FROM /dmo/carrier
  FIELDS carrier_id,
         name,
         currency_code
  ORDER BY carrier_id
  INTO TABLE @DATA(carriers).

For this course, however, we will not leave the database code in the executable class.

7. Why not put everything in one class?

This would work:

text
Console class
  ├─ SELECT
  ├─ filters
  ├─ loops
  └─ output

But it gives one class several responsibilities.

Instead:

text
ZCL_SQL_L01_###
Runner
        ↓ calls
ZCL_CARRIER_READER_###
Reader
        ↓ ABAP SQL
/DMO/CARRIER

The Runner starts the example, creates objects, calls methods, and displays results.

The Reader knows how carrier data is read and contains the ABAP SQL.

OOP principle

The Runner is responsible for running the example.

The Reader is responsible for reading carrier data.

8. Is the Reader a service?

No.

We deliberately call it a Reader, not a "service class" or "business service."

Later in RAP, business service has a specific meaning involving concepts such as:

text
CDS data model
RAP behavior
service definition
service binding

The Reader is an OOP data-access abstraction. A RAP business service is a different architectural concept with its own repository objects and responsibilities.

9. Create the Reader class

Create:

text
ZCL_CARRIER_READER_###

Description:

text
Lesson 1 - Carrier Reader

It does not implement IF_OO_ADT_CLASSRUN.

10. Define public result types

Use:

abap
CLASS zcl_carrier_reader_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.

    TYPES:
      BEGIN OF ty_carrier,
        carrier_id    TYPE /dmo/carrier-carrier_id,
        name          TYPE /dmo/carrier-name,
        currency_code TYPE /dmo/carrier-currency_code,
      END OF ty_carrier,

      tt_carriers TYPE STANDARD TABLE OF ty_carrier
        WITH EMPTY KEY.

ENDCLASS.

ty_carrier represents one result row.

tt_carriers represents many result rows.

11. Add GET_ALL

Add:

abap
METHODS get_all
  RETURNING VALUE(carriers) TYPE tt_carriers.

Complete definition:

abap
CLASS zcl_carrier_reader_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.

    TYPES:
      BEGIN OF ty_carrier,
        carrier_id    TYPE /dmo/carrier-carrier_id,
        name          TYPE /dmo/carrier-name,
        currency_code TYPE /dmo/carrier-currency_code,
      END OF ty_carrier,

      tt_carriers TYPE STANDARD TABLE OF ty_carrier
        WITH EMPTY KEY.

    METHODS get_all
      RETURNING VALUE(carriers) TYPE tt_carriers.

ENDCLASS.

12. Implement GET_ALL

abap
CLASS zcl_carrier_reader_### IMPLEMENTATION.

  METHOD get_all.

    SELECT FROM /dmo/carrier
      FIELDS carrier_id,
             name,
             currency_code
      ORDER BY carrier_id
      INTO TABLE @carriers.

  ENDMETHOD.

ENDCLASS.

carriers already exists as the returning parameter, so the SQL result is written into it.

13. Understand the SELECT

abap
SELECT FROM /dmo/carrier

selects the data source.

abap
FIELDS carrier_id,
       name,
       currency_code

requests only the fields we need.

abap
ORDER BY carrier_id

defines the row order. Without ORDER BY, result order is not guaranteed.

abap
INTO TABLE @carriers

places the multi-row result into an ABAP internal table.

Activate the Reader with:

text
Ctrl + F3

14. Create the Runner

Create:

text
ZCL_SQL_L01_###

This class does implement:

text
IF_OO_ADT_CLASSRUN

Start with:

abap
CLASS zcl_sql_l01_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

ENDCLASS.


CLASS zcl_sql_l01_### IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.

    out->write( 'Lesson 1' ).

  ENDMETHOD.

ENDCLASS.

Activate and run with:

text
F9

15. Create and use the Reader object

Replace main with:

abap
METHOD if_oo_adt_classrun~main.

  DATA(reader) = NEW zcl_carrier_reader_###( ).

  DATA(carriers) = reader->get_all( ).

  out->write( carriers ).

ENDMETHOD.

Now the flow is:

text
F9

Runner

Reader object

GET_ALL

ABAP SQL

/DMO/CARRIER

Reader returns internal table

Runner writes output

The Runner contains no direct carrier SELECT.

16. Add GET_BY_CURRENCY

In the Reader definition:

abap
METHODS get_by_currency
  IMPORTING
    currency TYPE /dmo/carrier-currency_code
  RETURNING
    VALUE(carriers) TYPE tt_carriers.

Implementation:

abap
METHOD get_by_currency.

  SELECT FROM /dmo/carrier
    FIELDS carrier_id,
           name,
           currency_code
    WHERE currency_code = @currency
    ORDER BY carrier_id
    INTO TABLE @carriers.

ENDMETHOD.

17. Host variables and @

In:

abap
WHERE currency_code = @currency

currency_code is a SQL source field.

currency is an ABAP method parameter.

ABAP host variables inside ABAP SQL are marked with @.

18. Call GET_BY_CURRENCY

In the Runner:

abap
METHOD if_oo_adt_classrun~main.

  DATA(reader) = NEW zcl_carrier_reader_###( ).

  DATA currency TYPE /dmo/carrier-currency_code VALUE 'USD'.

  DATA(carriers) =
    reader->get_by_currency( currency = currency ).

  out->write( carriers ).

ENDMETHOD.

Use a currency that exists in your Data Preview.

The filtering stays in the Reader because the Reader owns the query.

19. Add GET_BY_ID

Add to the Reader:

abap
METHODS get_by_id
  IMPORTING
    carrier_id TYPE /dmo/carrier-carrier_id
  EXPORTING
    carrier    TYPE ty_carrier
    found      TYPE abap_bool.

Implementation:

abap
METHOD get_by_id.

  CLEAR:
    carrier,
    found.

  SELECT SINGLE FROM /dmo/carrier
    FIELDS carrier_id,
           name,
           currency_code
    WHERE carrier_id = @carrier_id
    INTO @carrier.

  IF sy-subrc = 0.
    found = abap_true.
  ENDIF.

ENDMETHOD.

20. Why SELECT SINGLE?

carrier_id is the complete key of /DMO/CARRIER.

Therefore:

abap
WHERE carrier_id = @carrier_id

identifies at most one carrier record.

That is an appropriate use of SELECT SINGLE.

Do not think of it as "give me any one matching row."

21. Call GET_BY_ID

Use a carrier ID that exists in your system.

abap
METHOD if_oo_adt_classrun~main.

  DATA(reader) = NEW zcl_carrier_reader_###( ).

  DATA carrier_id TYPE /dmo/carrier-carrier_id VALUE 'LH'.

  reader->get_by_id(
    EXPORTING
      carrier_id = carrier_id
    IMPORTING
      carrier    = DATA(carrier)
      found      = DATA(found)
  ).

  IF found = abap_true.
    out->write( carrier ).
  ELSE.
    out->write( 'Carrier not found' ).
  ENDIF.

ENDMETHOD.

Replace 'LH' if necessary.

Test both an existing and a non-existing ID.

22. Why is sy-subrc checked in the Reader?

The Reader performs the SELECT SINGLE, so it checks the immediate database result.

The Runner receives a simpler API:

text
carrier
found

This keeps database-specific handling close to the database-access code.

23. Process returned data

Returned data is normal ABAP data:

abap
DATA(carriers) = reader->get_all( ).

LOOP AT carriers INTO DATA(carrier).

  out->write(
    |{ carrier-carrier_id } - { carrier-name }|
  ).

ENDLOOP.

The Reader reads.

The Runner decides how to present the result.

24. Lesson 1 architecture

text
┌────────────────────────────┐
│ ZCL_SQL_L01_###            │
│ Runner                     │
│ - creates Reader           │
│ - calls Reader methods     │
│ - writes console output    │
└──────────────┬─────────────┘


┌────────────────────────────┐
│ ZCL_CARRIER_READER_###     │
│ Reader                     │
│ - GET_ALL                  │
│ - GET_BY_CURRENCY          │
│ - GET_BY_ID                │
│ - contains ABAP SQL        │
└──────────────┬─────────────┘


┌────────────────────────────┐
│ /DMO/CARRIER               │
│ Persistent data            │
└────────────────────────────┘

25. Where is this going?

Today:

text
Runner

Reader

Database Table

Next, CDS adds a reusable data-model layer:

text
Runner

Reader

CDS View Entity

Database Table

Later, RAP introduces a different and richer architecture:

text
Consumer

Business Service

RAP Behavior

CDS Data Model

Persistence

The Reader is useful for learning OOP responsibility and data access. It is not a replacement for RAP architecture.

26. Common mistakes

Putting SQL back in the Runner

Keep carrier SQL in:

text
ZCL_CARRIER_READER_###

Calling the Reader a business service

Do not name it ZCL_CARRIER_SERVICE_### in this lesson. RAP business service means something different.

Missing @

Wrong:

abap
WHERE currency_code = currency

Correct:

abap
WHERE currency_code = @currency

Assuming database order

If order matters:

abap
ORDER BY carrier_id

Using SELECT * by default

Prefer explicit fields when only certain columns are required.

Treating SQL Console as application code

SQL Console is an ADT development tool for running and analyzing queries. The query you test there still needs to be placed in the appropriate application data-access code when the application needs it.

Looking for a connection string

The Runner and Reader execute in the ABAP backend. Ordinary ABAP SQL uses the platform's database access infrastructure.

27. Summary

You learned two architectures.

Runtime:

text
ADT

ABAP backend

ABAP SQL / database interface

System database

Development workflow:

text
Data Preview → inspect data
SQL Console  → explore a query
Reader       → application data access

Code organization:

text
Runner

Reader

ABAP SQL

Database Table

The main lesson is:

Learning database access does not mean putting database code everywhere.

For this lesson, the Reader owns data access and the Runner owns execution/output.

Next, CDS will give the Reader a reusable data model to read from.