Erste Schritte
Grundlegende Methoden und Konzepte anwenden
Mit lokalen Klassen arbeiten
Daten aus der Datenbank lesen
Mit strukturierten Datenobjekten arbeiten
Mit komplexen internen Tabellen arbeiten
Datenbankänderungen mit Business Objects implementieren
Das ABAP-RESTful-Anwendungsprogrammiermodell beschreiben

Grundlegende SELECT-Anweisungen implementieren

Objectives

After completing this lesson, you will be able to:
  • Die grundlegenden Funktionen von ABAP SQL beschreiben.
  • Einzelwerte von der Datenbank lesen.

Grundlegende ABAP-SQL-Syntax

Structured Query Language (SQL)

Alle relationalen Datenbanksysteme nutzen eine Variante der Structured Query Language (SQL), um Ihnen zu ermöglichen, mit ihnen zu arbeiten. Standard-SQL besteht aus drei Hauptkomponenten:

Data Manipulation Language (DML)
DML enthält die Anweisungen, die Sie für das Arbeiten mit den Informationen in Datenbanktabellen benötigen. Dabei handelt es sich im Einzelnen um die Anweisungen INSERT zum Hinzufügen neuer Datensätze, SELECT zum Lesen von Daten, UPDATE zum Ändern vorhandener Datensätze und DELETE zum Löschen von Tabelleninhalten. Diese Anweisungen werden in ABAP in Form von ABAP SQL abgebildet.
Data Definition Language (DDL)
Die Data Definition Language stellt Befehle zum Anlegen und Löschen von Datenbanktabellen und weiteren Datenbankartefakten wie Schemata, Tabellenindizes und Views bereit. In einem SAP-System führen Sie diese Aufgaben mit dedizierten ADT-Editoren und nicht mit ABAP-Programmen durch. Ein Beispiel ist der Editor für Datenbanktabellendefinitionen, den wir zuvor gesehen haben.
Data Control Language (DCL)
Mit der Data Control Language schränken Sie in SQL den Datenbankzugriff eines bestimmten Benutzers ein. Sie wird in ABAP nicht in ihrer klassischen Form eingesetzt, da die Benutzer auf Datenbankebene nicht eins zu eins den Endbenutzern entsprechen. Folglich verfügt ABAP über ein eigenes Berechtigungskonzept.

ABAP-SQL-Architektur

Früher mussten SAP-Systeme eine ganze Reihe von Datenbankplattformen unterstützen, und jede Plattform implementierte den SQL-Standard leicht unterschiedlich. Das bedeutete, dass jede Plattform leicht unterschiedliche Befehle für eine bestimmte Aufgabe benötigte. Um zu vermeiden, dass der ABAP-Quelltext datenbankspezifisch ist, hat die SAP ABAP SQL (oder Open SQL, wie es ursprünglich genannt wurde) erfunden.

Notiz

Die Namensänderung von Open SQL zu ABAP SQL zeigt auch, dass ABAP ab Release 7.53 nur SAP HANA als DBMS unterstützt.

ABAP SQL ist eine abstrakte Menge von SQL-Befehlen, die auf ABAP-Ebene implementiert und in die ABAP-Sprache integriert sind. Zur Laufzeit wird ABAP SQL in eine Variante von SQL übersetzt, die die Datenbank versteht. Diese Variante wird Native SQL genannt, um sie von ABAP SQL, der in ABAP integrierten SQL-Variante, zu unterscheiden. Die Übersetzung von ABAP SQL in Native SQL findet in der Datenbankschnittstelle statt, einer Komponente des ABAP-Systems, die aus einem allgemeinen Teil und einer datenbankspezifischen Bibliothek besteht.

Obwohl neuere ABAP-Releases nur SAP HANA als DBMS unterstützen, hat SAP das Konzept von ABAP SQL und der Datenbankschnittstelle beibehalten. Dafür gibt es folgende Gründe:

Kompatibilität der Architektur
ABAP SQL und die Datenbankschnittstelle sind integraler Bestandteil der Systemarchitektur.
Kompatibilität des Quelltextes
ABAP-SQL-Coding aus früheren SAP-Produkten (einschließlich kundenspezifischer Entwicklungen) sollte in den modernen, nur auf SAP HANA basierenden ABAP-Umgebungen ohne Nebeneffekte ausgeführt werden.
Aufgaben der Datenbankschnittstelle
Die Datenbankschnittstelle übersetzt nicht nur Anweisungen, sondern ist auch für ABAP-spezifische Aufgaben wie z.B. die automatische Mandantenbehandlung zuständig.

Einzelsatz aus der Datenbank auslesen

Die SELECT-Anweisung in ABAP

Um Daten aus der Datenbank zu lesen, verwenden Sie die SELECT-Anweisung.

Wenn Sie in ABAP SQL eine SELECT-Anweisung schreiben, vergleicht die Syntaxprüfung das, was Sie geschrieben haben, mit der Definition der Tabellen und Views. Wenn Sie versuchen, nicht vorhandene Tabellen, Views oder Felder zu adressieren, führt dies zu einem Syntaxfehler.

Die Grundsyntax der SELECT-Anweisung enthält mehrere Abschnitte – so genannte Klauseln – und folgt stets dem in der Abbildung „Die SELECT-Anweisung in ABAP" gezeigten Muster. Die wichtigsten Klauseln einer SELECT-Anweisung lauten wie folgt:

FROM
In der FROM-Klausel der SELECT-Anweisung geben Sie die Datenquelle an, aus der Sie lesen möchten. Dabei kann es sich entweder um eine Datenbanktabelle oder um eine View handeln. Spezielle SQL-Methoden ermöglichen es Ihnen, Daten aus mehreren Quellen in derselben SELECT-Anweisung zu kombinieren.
FELDER
In der FIELDS-Klausel der SELECT-Anweisung listen Sie die auszulesenden Spalten der Datenbanktabelle auf. Die Spalten in der Liste müssen durch Kommata getrennt sein. Wenn Sie die komplette Tabellenzeile lesen möchten, können Sie statt einer Spaltenliste auch „FIELDS *" angeben. Beachten Sie jedoch, dass dies zu einer erheblich größere Arbeitsbelastung für die Datenbank führen könnte, als nur die benötigten Spalten zu lesen.
WHERE

In der WHERE-Klausel können Sie eine Bedingung angeben, die beschreibt, welche Zeilen der Tabelle gelesen werden sollen. Die Bedingung „WHERE carrier_id = 'LH'" bedeutet beispielsweise, dass nur solche Zeilen gelesen werden, deren Spalte CARRIER_ID den Wert LH enthält.

Die WHERE-Klausel kann mehrere Bedingungen enthalten, die über die Operatoren AND und OR miteinander verknüpft werden. Beispielsweise würden „WHERE carrier_id = 'LH'" und „connection_id = '0400'" die Daten der Flugverbindung LH 0400 zurückgeben. Über den Operator NOT können Sie Bedingungen auch negieren. Die WHERE-Klausel ist die einzige optionale Klausel. Beachten Sie jedoch, dass Sie ohne WHERE-Klausel alle Daten aus der Tabelle auslesen bzw. – wenn die Tabelle ein Mandantenfeld aufweist – alle Daten, die zum Anmeldemandanten des Benutzers gehören. SELECT-Anweisungen ohne WHERE-Klausel können zu schwerwiegenden Performanceproblemen führen und sollten vermieden werden.

INTO
Mit der INTO-Klausel werden die Variablen im ABAP-Programm festgelegt, in die die Daten abgelegt werden sollen. Hierbei handelt es sich normalerweise um eine Struktur oder um eine interne Tabelle. Die Abfolge der Komponenten sollte mit der Reihenfolge der Spaltenliste in der FIELDS-Klausel identisch sein.

Notiz

In ABAP werden Sie auch anderen Formen von SQL-Syntax begegnen. Diese sind älter und wurden aus Kompatibilitätsgründen beibehalten. Sie sollten sich angewöhnen, die moderne Syntax zu verwenden, da sie weitaus mehr Funktionen und Features bietet als die alte Form.

Die Abbildung „Beispiel 1: Einzelfeld eines Einzelsatzes auslesen" veranschaulicht eine SELECT-Anweisung, die einen Einzelwert aus der Datenbank liest. Die FROM-Klausel besagt, dass die Anweisung aus der Datenbanktabelle /DMO/CONNECTION liest. Die Option SINGLE hinter dem Schlüsselwort SELECT zeigt an, dass nur eine Zeile (ein Einzelsatz) gelesen wird. Diese Zeile wird in der WHERE-Klausel identifiziert, indem Schlüsselfilterwerte für die Schlüsselfelder „carrier_id" und „connection_id" angegeben werden. Beachten Sie, dass die Datenbankschnittstelle einen Filter für den verbleibenden Schlüsselfeldmandanten hinzufügt.

Die FIELDS-Klausel listet nur eine Spalte der Tabelle auf: Spalte AIRPORT_FROM_ID.

Die INTO-Klausel muss mit dem Rest der Anweisung übereinstimmen. In unserem Beispiel wird hiermit die Variable „airport_from_id" als Zielobjekt angegeben. Es handelt sich um ein skalares Datenobjekt vom gleichen Typ wie das Tabellenfeld „airport_from_id".

Notiz

Das At-Zeichen (@) identifiziert „airport_from_id" als Name eines ABAP-Datenobjekts. Es ist für alle Variablen und Konstanten obligatorisch, die Sie in einer ABAP-SQL-Anweisung verwenden. Es wird benötigt, um Mehrdeutigkeiten zu vermeiden, wenn z.B. ein Datenobjekt und ein Tabellenfeld den gleichen Namen aufweisen.

Die Abbildung „Beispiel 2: Mehrere Felder eines Einzelsatzes auslesen" zeigt eine SELECT-Anweisung, die zwei Werte aus demselben Satz der Datenbank liest.

Dieses Mal listet die FIELDS-Klausel zwei Spalten der Tabelle auf: die Spalte AIRPORT_FROM_ID und die Spalte AIRPORT_TO_ID.

Für eine Übereinstimmung gibt die INTO-Klausel die Variablen „airport_from_id" und „airport_to_id" als Zielobjekte an. Sie werden durch ein Komma getrennt und in Klammern eingeschlossen, um deutlich zu machen, dass sie zusammen das Ziel der SELECT-Anweisung bilden.

Bei der Implementierung einer SELECT-Anweisung muss immer berücksichtigt werden, dass es zu keinem Ergebnis kommen kann, entweder weil die Datenbanktabelle gar keine Daten enthält oder weil sie keine Zeilen enthält, die die Bedingungen in der WHERE-Klausel erfüllen. Im Beispiel aus der obigen Abbildung enthält die Datenbanktabelle keine Zeile mit „carrier_id = 'XX'" und „connection_id = '1234'".

ABAP SQL verwendet das Systemfeld SY-SUBRC, um eine erfolgreiche oder nicht erfolgreiche Ausführung einer Anweisung anzuzeigen. Das Systemfeld SY-SUBRC ist vom Typ Integer. Der Initialwert 0 zeigt immer eine erfolgreiche Ausführung an. Wenn SY-SUBRC nach einer SELECT-Anweisung den Wert 4 enthält, bedeutet dies, dass die Datenbank ein leeres Ergebnis zurückgegeben hat.

Wenn die Datenbank ein leeres Ergebnis zurückgibt, fasst ABAP SQL die Zielvariable hinter INTO NICHT an!

Insbesondere wird die Zielvariable beim Auftreten eines Fehlers nicht initialisiert.

Es wird empfohlen, den Inhalt des Systemfelds „sy-subrc" unmittelbar nach jeder SELECT-Anweisung auszuwerten.

Probieren Sie es aus: SELECT-Beispiele

  1. Legen Sie wie in der ersten Übung dieser Schulung eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
    DATA airport_from_id TYPE /DMO/airport_from_id. DATA airport_to_id TYPE /DMO/airport_to_id. DATA airports TYPE TABLE OF /DMO/airport_from_id. * Example 1: Single field from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO @airport_from_id. out->write( `----------` ). out->write( `Example 1:` ). out->write( |Flight LH 400 departs from { airport_from_id }.| ). * Example 2: Multiple Fields from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO ( @airport_from_id, @airport_to_id ). out->write( `----------` ). out->write( `Example 2:` ). out->write( |Flight LH 400 flies from { airport_from_id } to { airport_to_id }| ). * Example 3: Empty Result and sy-subrc ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'XX' AND connection_id = '1234' INTO @airport_from_id. IF sy-subrc = 0. out->write( `----------` ). out->write( `Example 3:` ). out->write( |Flight XX 1234 departs from { airport_from_id }.| ). ELSE. out->write( `----------` ). out->write( `Example 3:` ). out->write( |There is no flight XX 1234, but still airport_from_id = { airport_from_id }!| ). ENDIF.
  3. Drücken Sie STRG + F3, um die Klasse zu aktivieren, und F9, um sie als Konsolen-App auszuführen.
  4. Analysieren Sie die Konsolenausgabe. Debuggen Sie das Programm, und probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen.

Daten aus einer Datenbanktabelle auslesen

In dieser Übung erweitern Sie Ihre lokale Klasse um Attribute für den Abflughafen und den Zielflughafen und lesen die Werte für diese Attribute aus einer Datenbanktabelle aus.

Vorlage:

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR (globale Klasse)

Lösung:

  • /LRN/CL_S4D400_DBS_SELECT (globale Klasse)

Aufgabe 1: Vorlage kopieren

Kopieren Sie die Vorlageklasse. Alternativ können Sie Ihre Lösung aus der vorherigen Übung kopieren.

Schritte

  1. Kopieren Sie die Klasse /LRN/CL_S4D400_CLS_CONSTRUCTOR in eine Klasse in Ihrem eigenen Paket (Namensvorschlag: ZCL_##_SELECT, wobei ## für Ihre Gruppennummer steht).

    1. Öffnen Sie den Quelltext der globalen Klasse /LRN/CL_S4D400_CLS_CONSTRUCTOR.

    2. Verknüpfen Sie die View Project Explorer mit dem Editor.

    3. Klicken Sie in der View Project Explorer mit der rechten Maustaste auf die Klasse /LRN/CL_S4D400_CLS_CONSTRUCTOR, um das Kontextmenü zu öffnen.

    4. Wählen Sie im Kontextmenü Duplicate ...

    5. Geben Sie den Namen Ihres Pakets in das Feld Package ein. Geben Sie im Feld Name den Namen ZCL_##_SELECT ein, wobei ## für Ihre Gruppennummer steht.

    6. Passen Sie die Beschreibung an, und wählen Sie Next.

    7. Bestätigen Sie den Transportauftrag, und wählen Sie Finish.

Aufgabe 2: Zusätzliche Attribute deklarieren

Erweitern Sie die lokale Klasse lcl_connection um die privaten Instanzattribute airport_from_id und airport_to_id. Fügen Sie der Implementierung der Methode get_output Ausgabedaten für die neuen Attribute hinzu.

Notiz

Die neuen Attribute sind noch nicht gefüllt. Um sie zu füllen, fügen wir dem Konstruktor in einer der nächsten Aufgaben dieser Übung eine SELECT-Anweisung hinzu.

Schritte

  1. Wechseln Sie in die lokale Klasse lcl_connection.

    1. Wählen Sie in der globalen Klasse Local Types.

  2. Fügen Sie der Klassendefinition folgende private Attribute hinzu:

    Attribute

    AttributnameUmfangDatentyp
    airport_from_idInstanz/DMO/AIRPORT_FROM_ID
    airport_to_idInstanz/DMO/AIRPORT_TO_ID
    1. Passen Sie den Quelltext wie folgt an:

      Code Snippet
      12345678910
      PRIVATE SECTION. DATA carrier_id TYPE /dmo/carrier_id. DATA connection_id TYPE /dmo/connection_id. DATA airport_from_id TYPE /dmo/airport_from_id. DATA airport_to_id TYPE /dmo/airport_to_id. ENDCLASS.
  3. Erweitern Sie die Implementierung der Methode get_output. Hängen Sie weitere Zeichenketten-Templates an den Returning-Parameter r_output an. Betten Sie die neuen Attribute als Ausdrücke in die Zeichenketten-Templates ein.

    1. Navigieren Sie zur Implementierung der Methode get_output.

    2. Passen Sie den Quelltext wie folgt an:

      Code Snippet
      1234567
      APPEND |--------------------------------| TO r_output. APPEND |Carrier: { carrier_id }| TO r_output. APPEND |Connection: { connection_id }| TO r_output. APPEND |Departure: { airport_from_id }| TO r_output. APPEND |Destination: { airport_to_id }| TO r_output.
  4. Aktivieren Sie die Klasse. Führen Sie sie aus, und analysieren Sie die Konsolenausgabe.

    1. Drücken Sie Strg + F3, um die Klasse zu aktivieren.

    2. Drücken Sie F9, um die Klasse auszuführen.

Aufgabe 3: Die Datenbanktabelle analysieren

Analysieren Sie die Definition der Datenbanktabelle /DMO/CONNECTION.

Schritte

  1. Öffnen Sie das Entwicklungsobjekt, das die Definition der Datenbanktabelle /DMO/CONNECTION enthält.

    1. Wählen Sie in der Eclipse-Symbolleiste ///Open ABAP Development Object, oder drücken Sie Strg + Umschalt + A.

    2. Geben Sie im Eingabefeld als Suchzeichenfolge /dmo/con ein.

    3. Klicken Sie in der Liste der passenden Einträge auf /DMO/CONNECTION (Datenbanktabelle), und wählen Sie OK.

  2. Öffnen Sie die Elementinformationen (F2) für die Datenbanktabelle /DMO/CONNECTION.

    1. Klicken Sie auf /dmo/connection nach dem Schlüsselwort define table, und drücken Sie F2, um die Elementinformationen anzuzeigen.

Aufgabe 4: Daten aus der Datenbank lesen

Implementieren Sie im Methodenkonstruktor der lokalen Klasse lcl_connection eine SELECT-Anweisung, die Werte für die neuen Attribute aus der Datenbanktabelle /DMO/CONNECTION liest.

Schritte

  1. Kehren Sie zur lokalen Klasse lcl_connection in Ihrer globalen Klasse zurück.

    1. Öffnen Sie in der Editor-View von Eclipse die Registerkarte ZCL_##_SELECT.

    2. Wählen Sie in der globalen Klasse Local Types.

  2. Navigieren Sie zur Implementierung der Methode constructor.

    1. Suchen Sie nach der Quelltextzeile METHOD constructor..

  3. Fügen Sie nach der Anweisung ENDIF. eine SELECT-Anweisung hinzu, die einen Einzelsatz aus der Datenbanktabelle /DMO/CONNECTION liest.

    1. Passen Sie den Quelltext wie folgt an:

      Code Snippet
      123456789
      IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. SELECT SINGLE FROM /dmo/connection
  4. Implementieren Sie die FIELDS-Klausel. Lesen Sie die Tabellenfelder airport_from_id und airport_to_id.

    Hinweis

    Verwenden Sie die automatische Vervollständigung (Strg + Leertaste), um die Feldnamen einzugeben.
    1. Geben Sie nach FROM /DMO/CONNECTIONFIELDS ein.

    2. Drücken Sie nach einem Leerzeichen Strg + Leertaste, und wählen Sie airport_from_id.

    3. Drücken Sie nach einem Komma und einem Leerzeichen erneut Strg + Leertaste, und wählen Sie airport_to_id.

    4. Die vollständige FIELDS-Klausel sollte wie folgt aussehen:

      Code Snippet
      123
      FIELDS airport_from_id, airport_to_id
  5. Implementieren Sie die WHERE-Bedingung. Schränken Sie alle Schlüsselfelder der Datenbanktabelle (mit Ausnahme des Mandantenfeldes) mit den Werten der Importing-Parameter i_carrier_id und i_connection_id ein. Vergessen Sie nicht, als Escape-Zeichen für die Parameter das Präfix @ voranzustellen.

    Hinweis

    Verwenden Sie die automatische Vervollständigung (Strg + Leertaste), um die Element- und Parameternamen einzugeben.
    1. Fügen Sie den folgenden Quelltext nach der FIELDS-Klausel hinzu:

      Code Snippet
      1234
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id
  6. Implementieren Sie die INTO-Klausel. Speichern Sie das SELECT-Ergebnis in den Attributen airport_from_id und airport_to_id. Vergessen Sie nicht, als Escape-Zeichen für die Attribute das Präfix @ voranzustellen.

    Hinweis

    Verwenden Sie die automatische Vervollständigung (Strg + Leertaste), um die Attributnamen einzugeben.
    1. Passen Sie den Quelltext wie folgt an:

      Code Snippet
      123456
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
    2. Die vollständige SELECT-Anweisung sollte wie folgt aussehen:

      Code Snippet
      12345678
      SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
  7. Implementieren Sie die Fehlerbehandlung nach der SELECT-Anweisung. Überprüfen Sie den Inhalt des Systemfeldes sy-subrc. Wenn er ungleich Null ist, muss die Ausnahme CX_ABAP_INVALID_VALUE ausgelöst werden.

    1. Fügen Sie den folgenden Quelltext nach der SELECT-Anweisung hinzu:

      Code Snippet
      12345
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF.
  8. Aktivieren Sie die Klasse. Führen Sie sie aus, und analysieren Sie die Konsolenausgabe. Prüfen Sie, ob die Ausgabe für die neuen Attribute Daten anzeigt.

    1. Drücken Sie Strg + F3, um die Klasse zu aktivieren.

    2. Drücken Sie F9, um die Klasse auszuführen.