Objectives
After completing this lesson, you will be able to:
- Komplexe interne Tabellen mit Daten füllen.
- Zugriff auf den Inhalt komplexer interner Tabellen.
- Verwenden Sie komplexe interne Tabellen in ABAP SQL.
Komplexe interne Tabellen füllen
Wie Sie bereits gelernt haben, lässt sich eine neue Zeile am einfachsten durch die Anweisung APPEND mit einem Datenobjekt, dessen Typ dem Zeilentyp der internen Tabelle entspricht, in eine interne Tabelle einfügen. Dieses Datenobjekt wird auch als „Arbeitsbereich" bezeichnet.
Bei einfachen internen Tabellen kann der in APPEND verwendete Arbeitsbereich eine skalare Variable, eine Konstante oder ein Literal sein. Bei komplexen internen Tabellen muss der Arbeitsbereich strukturiert sein.
Im Beispiel wird die strukturierte Variable connection verwendet, um die interne Tabelle connections zu füllen.
Grundsätzlich gibt es zwei Möglichkeiten, einen Arbeitsbereich connection zu deklarieren:
- Direkte Referenzierung des Zeilentyps st_connection
- Indirekte Referenzierung des Zeilentyps über LIKE LINE OF <internal_table>
Die Definition von Arbeitsbereichen mit LIKE LINE OF hat zwei Vorteile:
- Sie zeigt den Zweck der strukturierten Variablen als Arbeitsbereich für die interne Tabelle.
- Sie sorgt dafür, dass der Arbeitsbereich zur internen Tabelle passt, auch wenn sich die Definition der internen Tabelle ändert.
Wenn Sie den Arbeitsbereich nicht vor der APPEND-Anweisung füllen, wird die neue Zeile der internen Tabelle mit typspezifischen Initialwerten gefüllt.
Hinweis
Das gleiche Ergebnis erhalten Sie mit der Sondervariante APPEND INITIAL LINE TO <internal_table>. Für diese Variante ist nicht einmal ein Arbeitsbereich erforderlich.
Um den strukturierten Arbeitsbereich zu füllen, können Sie entweder die einzelnen Komponenten füllen oder, wie Sie im Beispiel sehen können, einen Ausdruck VALUE #( ) verwenden.
Wie im Beispiel zu sehen ist, können Sie auch einen Ausdruck VALUE #( ) direkt in der APPEND-Anweisung verwenden. In diesem Fall benötigen Sie keinen Arbeitsbereich.
Notiz
Dies kann sich positiv auf den gesamten Speicherverbrauch Ihres Programms auswirken.
Es gibt eine Variante des Ausdrucks VALUE #( ), die Sie einer internen Tabelle direkt zuweisen können. In dieser Variante von VALUE #( ) werden zusätzliche Klammerpaare verwendet, um die Tabellenzeilen voneinander zu trennen.
Das Code-Beispiel füllt die interne Tabelle carrier mit drei Zeilen, die jeweils einen anderen Wert für carrier_id und carrier_name aufweisen. Dadurch wird die Spalte currency_code nicht erwähnt, sondern mit dem typspezifischen Initialwert gefüllt.
Notiz
Mit der obigen Zuordnung werden alle vorhandenen Tabellenzeilen entfernt, bevor die Tabelle mit den neuen Zeilen gefüllt wird.
Um Daten zwischen namensgleichen Feldern zweier interner Tabellen zu kopieren, verwenden Sie den CORRESPONDING-Operator. Dies funktioniert ähnlich wie CORRESPONDING für Strukturen: Für jede Zeile der internen Quelltabelle legt das System eine neue Zeile in der internen Zieltabelle an und kopiert Daten zwischen namensgleichen Feldern. Quellfelder, für die es kein gleichnamiges Feld im Ziel gibt, werden nicht kopiert. Zielfelder, für die es kein gleichnamiges Feld in der Quelle gibt, werden mit typspezifischen Initialwerten gefüllt.
Im Beispiel enthält die interne Quelltabelle carrier drei Zeilen. Daher enthält die interne Zieltabelle connections nach der Wertzuweisung auch drei Zeilen.
Die Felder carrier_id und carrier_name sind in beiden internen Tabellen vorhanden. Sie werden von der Quelle in das Ziel kopiert. Das Feld currency_code ist nur in der Quelle vorhanden. Es wird nicht kopiert. Die Felder connection_id, airport_from_id und airport_to_id sind nur im Ziel vorhanden. Sie werden mit Initialwerten gefüllt.
Notiz
Wenn die interne Tabelle, die als Ziel dient, vor der Zuweisung Daten enthält, werden diese vom System gelöscht.
Komplexe interne Tabellen debuggen
Probieren Sie es aus: Komplexe interne Tabellen füllen
- Legen Sie wie in der ersten Übung dieser Schulung eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
- Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE STANDARD TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
carrier_name TYPE /dmo/carrier_name,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
TYPES tt_carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carriers TYPE tt_carriers.
* Example 1: APPEND with structured data object (work area)
**********************************************************************
* DATA connection TYPE st_connection.
" Declare the work area with LIKE LINE OF
DATA connection LIKE LINE OF connections.
* connection-carrier_id = 'NN'.
* connection-connection_id = '1234'.
* connection-airport_from_id = 'ABC'.
* connection-airport_to_id = 'XYZ'.
* connection-carrier_name = 'My Airline'.
" Use VALUE #( ) instead assignment to individual components
connection = VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline' ).
APPEND connection TO connections.
out->write( `--------------------------------` ).
out->write( `Example 1: APPEND with Work Area` ).
out->write( connections ).
* Example 2: APPEND with VALUE #( ) expression
**********************************************************************
APPEND VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline'
)
TO connections.
out->write( `----------------------------` ).
out->write( `Example 2: Append with VALUE` ).
out->write( connections ).
* Example 3: Filling an Internal Table with Several Rows
**********************************************************************
carriers = VALUE #( ( carrier_id = 'AA' carrier_name = 'American Airlines' )
( carrier_id = 'JL' carrier_name = 'Japan Airlines' )
( carrier_id = 'SQ' carrier_name = 'Singapore Airlines')
).
out->write( `-----------------------------------------` ).
out->write( `Example 3: Fill Internal Table with VALUE` ).
out->write( carriers ).
* Example 4: Filling one Internal Table from Another
**********************************************************************
connections = CORRESPONDING #( carriers ).
out->write( `--------------------------------------------` ).
out->write( `Example 4: CORRESPONDING for Internal Tables` ).
out->write( data = carriers
name = `Source Table CARRIERS:`).
out->write( data = connections
name = `Target Table CONNECTIONS:`).
- Drücken Sie STRG + F3 auf Ihrer Tastatur, um die Klasse zu aktivieren, und F9, um die Konsolen-App auszuführen.
- Analysieren Sie die Konsolenausgabe. Debuggen Sie das Programm, und probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen.
Zugriff auf komplexe interne Tabellen
Sie haben in diesem Kurs bereits gelernt, wie Sie mithilfe eines internen Tabellenausdrucks eine einzelne Zeile aus einer einfachen internen Tabelle abrufen. Dort wurde ein Indexzugriff verwendet, d.h., die Zeile wurde durch ihre Position in der internen Tabelle identifiziert. Dieser Indexzugriff funktioniert für komplexe interne Tabellen genauso. Für komplexe interne Tabellen werden dagegen interne Tabellenausdrücke mit Schlüsselzugriff wichtig, bei denen die Zeile durch ihren Inhalt identifiziert wird.
Notiz
Obwohl dies als Schlüsselzugriff bezeichnet wird, können beliebige Felder für die Selektion verwendet werden, nicht nur Schlüsselfelder der internen Tabelle. Wenn mehr als eine Zeile die Anforderung erfüllt, geben STANDARD-Tabellen die erste Zeile zurück, d.h. die Zeile mit dem niedrigsten Index.
Im Beispiel wird eine einzelne Zeile aus der internen Tabelle connections gelesen. Der Schlüssel dieser internen Tabelle besteht aus den Feldern carrier_id und connection_id, aber der Schlüsselzugriff verwendet airport_from_id und airport_to_id, um die Zeile zu identifizieren. Die interne Tabelle enthält zwei Verbindungen vom Flughafen SFO zu SIN, sodass die erste davon zurückgegeben wird.
Beachten Sie, dass die ABAP-Laufzeit die Ausnahme CX_SY_ITAB_LINE_NOT_FOUND auslöst, wenn keine der Zeilen die Bedingung erfüllt. Behandeln Sie diese Ausnahme zur Vermeidung von Laufzeitfehlern in einer Struktur TRY … CATCH … ENDTRY.
Wenn Sie mehrere Zeilen einer internen Tabelle verarbeiten möchten und diese unter Angabe von Feldern identifizieren möchten, verwenden Sie LOOP AT <interne Tabelle> INTO <Ziel> WHERE <Bedingung>. Die WHERE-Bedingung kann eine beliebige Anzahl konstituierender Ausdrücke enthalten, die durch AND und OR verknüpft sind. Innerhalb der Ausdrücke können Sie nicht nur das Gleichheitszeichen (=), sondern auch die Operatoren >, >=, <, <=, <> und BETWEEN verwenden.
Nach dem Einlesen des Inhalts einer Tabellenzeile in einen Arbeitsbereich möchten Sie unter Umständen Änderungen aus dem Arbeitsbereich zurück in die interne Tabelle schreiben. Eine Möglichkeit hierfür ist die Anweisung MODIFY TABLE.
Diese Anweisung ist ein Schlüsselzugriff, da das System den Inhalt der Schlüsselfelder im Arbeitsbereich verwendet, um die zu ändernde Tabellenzeile zu identifizieren. Sie überschreibt dann diese Tabellenzeile mit den Inhalten des Arbeitsbereichs.
Im Beispiel enthält der Arbeitsbereich carrier den Wert 'JL' im Schlüsselfeld carrier_id. Anhand dieses Werts identifiziert das System die zweite zu aktualisierende Zeile. Diese Zeile wird dann mit den Werten aus dem Arbeitsbereich aktualisiert.
Notiz
Mit MODIFY TABLE können nur Nicht-Schlüsselfelder geändert werden. Die Anweisung unterstützt keine Änderungen an Schlüsselfeldern.
Die MODIFY -Anweisung (ohne Schlüsselwort TABLE!) unterscheidet nicht zwischen Schlüsselfeldern und Nicht-Schlüsselfeldern. Sie überschreibt die gesamte Tabellenzeile mit neuen Werten aus dem Arbeitsbereich. Diese Anweisung gilt als Indexzugriff, da die zu aktualisierende Zeile durch ihre Position in der internen Tabelle identifiziert wird. In der Regel wird der Index explizit mit dem Zusatz INDEX, gefolgt von einem ganzzahligen Argument (Literal, Konstante, Variable, Ausdruck), angegeben.
Notiz
Es gibt auch eine spezielle Variante ohne den Zusatz INDEX. Wir werden diese Variante als Nächstes besprechen.
Im Beispiel verwendet die MODIFY -Anweisung den Zusatz INDEX, um die erste Tabellenzeile zu adressieren. In dieser Zeile werden alle Felder mit den Werten aus dem Arbeitsbereich überschrieben, auch das Schlüsselfeld carrier_id.
Es treten häufig Situationen auf, in denen Sie die Inhalte mehrerer oder sogar aller Zeilen einer internen Tabelle bearbeiten müssen. Dazu implementieren Sie eine Schleife über die Tabelle, die jede zu ändernde Zeile nacheinander in einen Arbeitsbereich stellt. Innerhalb der Schleife ändern Sie zunächst den Inhalt des Arbeitsbereichs. Anschließend schreiben Sie die Änderungen mit der MODIFY-Anweisung in die interne Tabelle zurück.
Notiz
Wenn Sie Ihre Änderungen nicht zurück in die Tabelle schreiben, gehen die Änderungen verloren, wenn der Arbeitsbereich mit den Daten aus der nächsten Zeile gefüllt wird.
Im Beispiel liest die Schleife alle Zeilen der internen Tabelle carriers, für die das Feld currency_code noch nicht gefüllt ist. Dies ist bei den letzten beiden Zeilen der Fall. Für jede dieser Zeilen ersetzt das Programm den Initialwert im Feld currency_code durch den neuen Wert „USD". Schließlich wird die aktuelle Zeile mithilfe der MODIFY-Anweisung mit den aktualisierten Werten überschrieben.
Anstatt den Index explizit anzugeben, wird im Quelltextbeispiel eine Kurzform der MODIFY-Anweisung verwendet, bei der der Zusatz INDEX fehlt. Diese Kurzform ist nur zwischen LOOP … ENDLOOP erlaubt. Nur dort kann das System implizit die Zeile aktualisieren, an der es gerade arbeitet.
Wenn Sie versuchen, MODIFY ohne INDEX außerhalb von LOOP … ENDLOOP zu verwenden, weiß das System nicht, welche Zeile bearbeitet werden soll, und löst einen nicht abfangbaren Laufzeitfehler aus. Um solche Laufzeitfehler zu vermeiden, achten Sie darauf, die zugehörige Warnung der Syntaxprüfung nicht zu ignorieren.
Try It Out: Zugriff auf komplexe interne Tabellen
- Legen Sie wie bei der ersten Übung dieses Kurses eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
- Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE SORTED TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
DATA connection LIKE LINE OF connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
DATA carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carrier LIKE LINE OF carriers.
* Preparation: Fill internal tables with data
**********************************************************************
connections = VALUE #( ( carrier_id = 'JL'
connection_id = '0408'
airport_from_id = 'FRA'
airport_to_id = 'NRT'
carrier_name = 'Japan Airlines'
)
( carrier_id = 'AA'
connection_id = '0017'
airport_from_id = 'MIA'
airport_to_id = 'HAV'
carrier_name = 'American Airlines'
)
( carrier_id = 'SQ'
connection_id = '0001'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'Singapore Airlines'
)
( carrier_id = 'UA'
connection_id = '0078'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'United Airlines'
)
).
carriers = VALUE #( ( carrier_id = 'SQ'
currency_code = ' '
)
( carrier_id = 'JL'
currency_code = ' '
)
( carrier_id = 'AA'
currency_code = ' '
)
( carrier_id = 'UA'
currency_code = ' '
)
).
* Example 1: Table Expression with Key Access
**********************************************************************
out->write( `--------------------------------------------` ).
out->write( `Example 1: Table Expressions with Key Access` ).
out->write( data = connections
name = `Internal Table CONNECTIONS: ` ).
" with key fields
connection = connections[ carrier_id = 'SQ'
connection_id = '0001' ].
out->write( data = connection
name = `CARRIER_ID = 'SQ' AND CONNECTION_ID = '001':` ).
" with non-key fields
connection = connections[ airport_from_id = 'SFO'
airport_to_id = 'SIN' ].
out->write( data = connection
name = `AIRPORT_FROM_ID = 'SFO' AND AIRPORT_TO_ID = 'SIN':` ).
* Example 2: LOOP with key access
**********************************************************************
out->write( `-------------------------------` ).
out->write( `Example 2: LOOP with Key Access` ).
LOOP AT connections INTO connection
WHERE airport_from_id <> 'MIA'.
"do something with the content of connection
out->write( data = connection
name = |This is row number { sy-tabix }: | ).
ENDLOOP.
* Example 3: MODIFY TABLE (key access)
**********************************************************************
out->write( `-----------------------------------` ).
out->write( `Example 3: MODIFY TABLE (key access` ).
out->write( data = carriers
name = `Table CARRRIERS before MODIFY TABLE:`).
carrier = carriers[ carrier_id = 'JL' ].
carrier-currency_code = 'JPY'.
MODIFY TABLE carriers FROM carrier.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY TABLE:`).
* Example 4: MODIFY (index access)
**********************************************************************
out->write( `--------------------------------` ).
out->write( `Example 4: MODIFY (index access)` ).
carrier-carrier_id = 'LH'.
carrier-currency_code = 'EUR'.
MODIFY carriers FROM carrier INDEX 1.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY:`).
* Example 5: MODIFY in a LOOP
**********************************************************************
out->write( `----------------------------` ).
out->write( `Example 5: MODIFY in a LOOP` ).
LOOP AT carriers INTO carrier
WHERE currency_code IS INITIAL.
carrier-currency_code = 'USD'.
MODIFY carriers FROM carrier.
ENDLOOP.
out->write( data = carriers
name = `Table CARRRIERS after the LOOP:`).
- Drücken Sie STRG + F3 auf Ihrer Tastatur, um die Klasse zu aktivieren, und F9, um die Konsolen-App auszuführen.
- Analysieren Sie die Konsolenausgabe. Debuggen Sie das Programm, und probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen.
Komplexe interne Tabellen in ABAP SQL
Die ABAP-SQL-Anweisung SELECT liest Daten aus einer Datenbanktabelle oder einer CDS-View. Wenn Sie die Option SINGLE verwenden, wird genau ein Datensatz aus der Datenbank gelesen, auch wenn mehr Daten vorhanden sind, die die Bedingungen in der WHERE-Klausel erfüllen.
Wie Sie bereits gelernt haben, ist eine Möglichkeit, dieses Einzelsatzergebnis zu erhalten, eine strukturierte Variable nach dem Schlüsselwort INTO.
Wenn Sie SELECT ohne SINGLE verwenden, geben Sie an, dass Sie an allen Datensätzen interessiert sind, die den Bedingungen in der WHERE-Klausel entsprechen. Sie müssen dann sicherstellen, dass Sie mehrere Datensätze empfangen und speichern können. Der offensichtliche Weg, dies zu tun, ist die Verwendung einer komplexen internen Tabelle als Ziel der SELECT -Anweisung. Dies ist möglich, erfordert aber den Zusatz TABLE zwischen dem Schlüsselwort INTO und dem Namen der internen Tabelle.
Im Beispiel möchten wir alle drei Flughäfen lesen, die mit London in Verbindung stehen, und nicht nur einen einzigen von ihnen. Daher wird das Schlüsselwort SINGLE nach SELECT weggelassen, das Schlüsselwort TABLE hinter INTO hinzugefügt und die interne Tabelle airports_full als Ziel der SELECT-Anweisung verwendet.
Das Beispiel verwendet eine explizite Feldliste hinter FIELDS, die den Spalten der internen Tabelle airports_full entspricht. Natürlich können Sie auch FIELDS *, INTO CORRESPONDING FIELDS OF TABLE und Aliasnamen in der Feldliste verwenden.
Das Beispiel verwendet FIELDS * statt einer expliziten Feldliste und INTO CORRESPONDING FIELDS OF TABLE statt INTO TABLE.
Da der Zeilentyp der internen Tabelle flughäfen nur zwei Komponenten AirportID und Name enthält, werden nur die gleichnamigen Felder von der Datenbank gelesen.
Wenn Sie DATA( ) in einer SELECT-Anweisung hinter dem Zusatz INTO TABLE verwenden, deklarieren Sie inline eine interne Tabelle. Der Zeilentyp dieser internen Tabelle wird aus der FIELDS -Klausel abgeleitet. Für Tabellenfelder und View-Elemente ist ein Aliasname optional. Für Ausdrücke in der FIELDS -Klausel ist ein Aliasname obligatorisch, wenn die INTO -Klausel eine Inline-Deklaration enthält.
Notiz
Inline-Deklarationen interner Tabellen werden nur hinter INTO TABLE unterstützt. Inline-Deklarationen können nicht hinter INTO CORRESPONDING FIELDS OF TABLE verwendet werden.
Inline deklarierte interne Tabellen sind immer Standardtabellen ohne Schlüssel. Sortierte Tabellen oder Hash-Tabellen können nicht mit Inline-Deklarationen deklariert werden. Dies kann zu Performanceproblemen führen, wenn Sie die interne Tabelle mit vielen Zeilen füllen und den Schlüsselzugriff sehr häufig verwenden.
Wenn Sie mehrere Datensätze aus der Datenbank lesen, werden einige spezielle SQL-Techniken besonders interessant. Eine dieser Techniken ist die UNION-Richtlinie, um die Ergebnisse mehrerer SELECT-Anweisungen zu kombinieren.
Die Abbildung zeigt die Kombination zweier SELECT-Ergebnisse:
Das erste SELECT -Ergebnis liest ID und NAME aller Carrier mit CurrencyCode = 'GBP'. Der zweite SELECT liest ID und NAME aller Flughäfen mit City = 'London'. Der erste SELECT gibt einen Datensatz zurück, der zweite SELECT gibt drei Datensätze zurück. Anstatt diese Ergebnisse separat abzurufen, werden sie zu einem Ergebnis mit vier Datensätzen kombiniert. Es ist wichtig, darauf hinzuweisen, dass dies innerhalb der Datenbank geschieht.
Voraussetzung für diese Technik ist natürlich, dass die beiden Ergebnisse miteinander kompatibel sind, d.h. dass sie die gleiche Anzahl von Feldern und die gleichen Feldnamen haben. Es ist jedoch nicht notwendig, dass die Typen der Felder identisch sind.
Die ABAP-SQL-Syntax für dieses Beispiel besteht aus zwei SELECT -Anweisungen. Jede SELECT-Anweisung hat ihre eigene FROM-Klausel, FIELDS-Klausel und WHERE-Klausel, aber ganz am Ende gibt es nur eine INTO-Klausel. Die beiden SELECT -Anweisungen sind durch Schlüsselwörter UNION ALL verbunden.
Notiz
Bei UNION statt UNION ALL würde die Datenbank nach Duplikaten suchen und diese eliminieren, bevor das Ergebnis zurückgegeben wird. Wir verwenden UNION ALL, um diese unnötige zusätzliche Last auf der Datenbank zu vermeiden.
Beide Feldlisten bestehen aus drei Elementen, wobei das erste und das zweite Element in beiden FIELDS -Klauseln identische Aliasnamen haben. Das dritte Feld benötigt keinen Alias, da der Feldname in beiden CDS-Views gleich ist.
Notiz
Das erste Element in FIELDS ist ein literaler Text, mit dem wir im kombinierten Ergebnis zwischen Fluggesellschaften und Flughäfen unterscheiden können.
Try It Out: Interne Tabellen in ABAP SQL
- Legen Sie wie in der ersten Übung dieses Kurses eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
- Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
TYPES: BEGIN OF st_airport,
airportid TYPE /dmo/airport_id,
name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE KEY airportid.
DATA airports TYPE tt_airports.
* Example 1: Structured Variables in SELECT SINGLE ... INTO ...
**********************************************************************
DATA airport_full TYPE /DMO/I_Airport.
SELECT SINGLE
FROM /DMO/I_Airport
FIELDS AirportID, Name, City, CountryCode
WHERE City = 'Zurich'
INTO @airport_full.
out->write( `-------------------------------------` ).
out->write( `Example 1: SELECT SINGLE ... INTO ...` ).
out->write( data = airport_full
name = `One of the airports in Zurich (Structure):` ).
* Example 2: Internal Tables in SELECT ... INTO TABLE ...
**********************************************************************
DATA airports_full TYPE STANDARD TABLE OF /DMO/I_Airport
WITH NON-UNIQUE KEY AirportID.
SELECT
FROM /DMO/I_Airport
FIELDS airportid, Name, City, CountryCode
WHERE City = 'London'
INTO TABLE @airports_full.
out->write( `------------------------------------` ).
out->write( `Example 2: SELECT ... INTO TABLE ...` ).
out->write( data = airports_full
name = `All airports in London (Internal Table):` ).
* Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE
**********************************************************************
SELECT
FROM /DMO/I_Airport
FIELDS *
WHERE City = 'London'
INTO CORRESPONDING FIELDS OF TABLE @airports.
out->write( `----------------------------------------------------------` ).
out->write( `Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE` ).
out->write( data = airports
name = `Internal Table AIRPORTS:` ).
* Example 4: Inline Declaration
**********************************************************************
SELECT
FROM /DMO/I_airport
FIELDS AirportID, Name AS AirportName
WHERE City = 'London'
INTO TABLE @DATA(airports_inline).
out->write( `----------------------------------------------------------` ).
out->write( `Example 4: Inline Declaration after INTO TABLE` ).
out->write( data = airports_inline
name = `Internal Table AIRPORTS_INLINE:` ).
** Example 4: ORDER BY and DISTINCT
***********************************************************************
*
* SELECT
* FROM /DMO/I_Airport
* FIELDS DISTINCT CountryCode
* ORDER BY CountryCode
* INTO TABLE @DATA(countryCodes).
*
* out->write( countryCodes ).
* Example 5: UNION (ALL)
**********************************************************************
SELECT FROM /DMO/I_Carrier
FIELDS 'Airline' AS type, AirlineID AS Id, Name
WHERE CurrencyCode = 'GBP'
UNION ALL
SELECT FROM /DMO/I_Airport
FIELDS 'Airport' AS type, AirportID AS Id, Name
WHERE City = 'London'
* ORDER BY type, Id
INTO TABLE @DATA(names).
out->write( `----------------------------------------------` ).
out->write( `Example 5: UNION ALL of Airlines and Airports ` ).
out->write( data = names
name = `ID and Name of Airlines and Airports:` ).
- Drücken Sie STRG + F3 auf Ihrer Tastatur, um die Klasse zu aktivieren, und F9, um die Konsolen-App auszuführen.
- Analysieren Sie die Konsolenausgabe. Debuggen Sie das Programm, und probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen.
Komplexe interne Tabelle verwenden
In dieser Übung deklarieren Sie ein tabellenartiges Attribut, füllen es mit einer SELECT-Anweisung und greifen auf den Inhalt zu.
Aufgabe 1: Vorlage kopieren
Kopieren Sie die Vorlageklasse. Alternativ können Sie Ihre Lösung aus der vorherigen Übung kopieren.
Schritte
Kopieren Sie die Klasse /LRN/CL_S4D400_STS_STRUCTURE in eine Klasse in Ihrem eigenen Paket (Namensvorschlag: ZCL_##_ITAB, wobei ## für Ihre Gruppennummer steht).
Öffnen Sie den Quelltext der globalen Klasse /LRN/CL_S4D400_STS_STRUCTURE.
Verknüpfen Sie die View Project Explorer mit dem Editor.
Klicken Sie in der View Project Explorer mit der rechten Maustaste auf die Klasse /LRN/CL_S4D400_STS_STRUCTURE, um das Kontextmenü zu öffnen.
Wählen Sie im Kontextmenü Duplicate ...
Geben Sie den Namen Ihres Pakets in das Feld Package ein. Geben Sie im Feld Name den Namen ZCL_##_ITAB ein, wobei ## für Ihre Gruppennummer steht.
Passen Sie die Beschreibung an, und wählen Sie Next.
Bestätigen Sie den Transportauftrag, und wählen Sie Finish.
Aufgabe 2: Interne Tabelle deklarieren
Deklarieren Sie in der lokalen Klasse ein statisches, tabellenartiges Attribut flughäfen, um Detailinformationen zu allen verfügbaren Flughäfen zu puffern. Definieren Sie zunächst einen privaten Strukturtyp st_flughafen und einen Tabellentyp tt_flughäfen innerhalb der lokalen Klasse.
Schritte
Wechseln Sie in die lokale Klasse lcl_connection.
Wählen Sie in der globalen Klasse Local Types.
Definieren Sie einen privaten Strukturtyp st_flughafen mit den folgenden Komponenten:
Komponenten des Strukturtyps st_flughafen:
| Komponentenname | Datentyp |
|---|
| AirportID | /dmo/airport_id |
| Name | /dmo/airport_name |
Passen Sie den Quelltext wie folgt an:
1234567891011121314
TYPES:
BEGIN OF st_details,
DepartureAirport TYPE /dmo/airport_from_id,
DestinationAirport TYPE /dmo/airport_to_id,
AirlineName TYPE /dmo/carrier_name,
END OF st_details.
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
Definieren Sie einen privaten Tabellentyp tt_flughäfen mit den folgenden Eigenschaften:
Eigenschaften des Tabellentyps tt_flughäfen:
| Eigenschaft | Wert |
|---|
| Zeilentyp | st_flughafen |
| Tabellenart | STANDARD TABLE |
| Schlüsseldefinition | NICHT-EINHEITLICHER STANDARDSCHLÜSSEL |
Passen Sie den Quelltext wie folgt an:
12345678910
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE DEFAULT KEY.
Deklarieren Sie ein neues privates statisches Attribut flughäfen und typisieren Sie es mit dem Tabellentyp tt_flughäfen.
Fügen Sie am Ende der Klassendefinition den folgenden Quelltext hinzu:
123
CLASS-DATA airports TYPE tt_airports.
Aufgabe 3: Statisches Attribut in einem Klassenkonstruktor füllen
Definieren Sie einen Klassenkonstruktor und implementieren Sie eine SELECT-Anweisung, die alle verfügbaren Flughäfen aus der CDS-View-Entität /DMO/I_Airport in das statische Attribut flughäfen liest.
Schritte
Fügen Sie der lokalen Klasse lcl_connection über einen Quickfix einen Klassenkonstruktor hinzu.
Setzen Sie den Cursor auf den Namen der Klasse, und drücken Sie Strg + 1.
Doppelklicken Sie auf Klassenkonstruktor generieren.
Implementieren Sie im Klassenkonstruktor eine SELECT -Anweisung, die alle Datensätze aus der CDS-View-Entität /DMO/I_Airport in das statische Attribut flughäfen liest.
Navigieren Sie zur Implementierung der Methode class_constructor.
Fügen Sie in der Methodenimplementierung den folgenden Quelltext hinzu:
12345
SELECT FROM /DMO/I_Airport
FIELDS AirportID, Name
INTO TABLE @airports.
Aufgabe 4: Zugriff auf den Inhalt der internen Tabelle
Verwenden Sie den Inhalt der internen Tabelle flughäfen in der Methode get_output, um die Flughafennamen zur Ausgabe hinzuzufügen.
Schritte
Navigieren Sie zur Implementierung der Methode get_output.
Fahren Sie wie in den vorangegangenen Übungen fort.
Lesen Sie zu Beginn der Methode die Details des Abflugflughafens in ein strukturiertes Datenobjekt flight.
Hinweis
Verwenden Sie einen Tabellenausdruck airports[ ... ] und eine Inline-Deklaration für das Datenobjekt escape.
Fügen Sie am Anfang der Methode den folgenden Code hinzu:
123
DATA(departure) = airports[ airportID = details-departureairport ].
Ebenso lesen Sie die Details des Zielflughafens in ein strukturiertes Datenobjekt destination.
Passen Sie den Quelltext wie folgt an:
1234
DATA(departure) = airports[ airportID = details-departureairport ].
DATA(destination) = airports[ airportID = details-destinationairport ].
Verwenden Sie den Komponentennamen der beiden Strukturen, um die Flughafennamen zur Ausgabe hinzuzufügen.
Passen Sie den Quelltext wie folgt an:
1234
APPEND |Departure: { details-departureairport } { departure-name }| TO r_output.
APPEND |Destination: { details-destinationairport } { destination-name }| TO r_output.
Optional: Verzichten Sie auf das strukturierte Datenobjekt und verwenden Sie die Tabellenausdrücke direkt in den Zeichenketten-Templates.
Kommentieren Sie die Codezeilen, in denen Sie die Strukturen für Abfahrt und Ziel füllen.
Ersetzen Sie im Zeichenketten-Template departure-name durch airports[ airportid = details-departureairport ]-name.
Ersetzen Sie destination-name analog durch airports[ airportid = details-destinationairport ]-name.
Aktivieren Sie die Klasse. Führen Sie sie aus, und analysieren Sie die Konsolenausgabe. Prüfen Sie, ob die Ausgabe Daten für alle Attribute anzeigt.
Drücken Sie Strg + F3, um die Klasse zu aktivieren.
Drücken Sie F9, um die Klasse auszuführen.