SAP ABAP WS 2008/2009 SAP ® und R/3 ® sind eingetragene Warenzeichen der SAP AG -1- Grobgliederung • Kapitel 1 o Einführung SAP • Kapitel 2 o Syntax o Datentypen o Kontrollstrukturen o Komplexe Strukturen • Kapitel 3 o Modularisierung o Datenbehandlung • Kapitel 4 o Objektorientierung • Kapitel 5 o Interne & Externe Tabellen • Kapitel 6 o Dynamische Programmierung -2- Einführung LOGIN – erste Anmeldung im System: Bei der Anmeldung im System ist zu beachten, das alle Angaben wie unten in das Anmeldeformular eingetragen werden. Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Das Kürzel LOGXX steht für das Ihnen zugewiesene Konto im SAP-System. Dabei ersetzen Sie bitte das XX durch Ihre Login-Nummer. Bei der erstmaligen Anmeldung ist das Initialkennwort „start01“. Nach Angabe des Kennworts werden Sie aufgefordert ein neues persönlichen Kennwort zu wählen. Bitte beachten Sie hier folgende Regeln: − Kennwort besteht aus 3 bis 8 Zeichen − keine Unterscheidung zwischen Groß- und Kleinschreibung − <?>, <!> dürfen nicht am Anfang stehen − <Leerzeichen> dürfen nicht in den ersten drei Zeichen enthalten sein − reservierte Worte sind <PASS> und <SAP*> − drei identische Buchstaben am Anfang werden nicht akzeptiert − Buchstabenfolgen, die drei oder mehr Buchstaben aus dem Benutzernamen enthalten werden nicht akzeptiert − keines der fünf zuletzt verwendeten Kennwörter ist zulässig − Kennwortänderung nur einmal am Tag zulässig Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Bildschirmaufbau: Sind Sie nun im System angemeldet, sehen Sie folgenden Bildschirmaufbau. Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Um Ihnen den Zugriff auf die wichtigen Menüpunkte zu erleichtern ziehen Sie bitte die Punkte „Dictionary“ und „ABAP-Editor“ mittels Drag and Drop auf „Favoriten“. Nun können Sie,ohne das Menü aufklappen zu müssen, jederzeit auf diese Elemente zugreifen. Im oberen Teil des Bildschirms befindet sich die Menüleiste und darunter die Symbolleiste. Links in der Symbolleiste liegt das Eingabefenster für die Transaktionscodes. Ganz unten liegt die Statusleiste. Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Enter: Bestätigen von Eingaben <Enter> Buchen: Sichern der getätigten Eingaben <F11> Zurück: Zurück zum vorhergehenden Fenster <F3> Beenden: Beenden einer Anwendung <Shift+F3> Abbrechen: Abbruch einer Transaktion ohne Speichern <F12> Suchen: Suchen nach bestimmten Inhalten <Strg+F> Drucken: Ausdrucken des aktuellen Bildschirminhaltes <Strg+P> Optionen: Layout anpassen, Einstellungen <Alt+F12> Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Um effektiver mit dem SAP-System arbeiten zu können empfielt es sich mehrere Modi (Fenster) gleichzeitig geöffnet zu haben, um schneller durch das System navigieren zu können. Sie haben drei verschiedene Möglichkeiten einen neuen Modi zu erzeugen: 1. Eingabe des Transaktionscodes: /o000 2. Menü: System Erzeugen Modus 3. Symbol: Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 Transaktionscodes: Man kann durch die Eingabe eines alphanumerischen Codes in das Eingabefeld der Symbolleiste direkt in bestimmte Transaktionen verzweigen. - eine Transaktion aufrufen: - im selben Modus: xxxx (xxxx = Transaktionscode) - in einem zusätzlichen Modus: /oxxxx (xxxx = Transaktionscode) - die aktuelle Transaktion beenden: /n - den aktuellen Modus löschen: /i - eine Modusliste erzeugen: /o - den Debugmodus einschalten: /h Über den Menüpfad SYSTEM STATUS kann man sich unter anderem den Transaktionscode der laufenden Anwendung anzeigen lassen. Um zu erfahren welchen Transaktionscode man benötigt um in das gegenwärtige Fenster zu gelangen einfach in der Statusleiste auf klicken. Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -7- Kapitel 5 Kapitel 6 Felder und Eingabehilfen: In einem SAP-System trifft man auf 3 verschiedene Arten von Feldern: 1. Muss-Feld: ist eines der Felder leer, so kann die Transaktion nicht fortgesetzt werden. 2. Kann-Feld: Felder dieser Art können leer gelassen werden. 3. Anzeigefelder: die Angaben dieser Felder können nicht geändert werden. versehen sind, kann eine Eingabehilfe aktiviert werden. Durch Klick auf Für Felder, die mit einem das Symbol oder <F4> werden die Eingabemöglichkeiten für das Feld angezeigt. Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -8- Kapitel 5 Kapitel 6 Matchcodesuche: Um schnell und zuverlässig bestimmte Daten im SAP-System zu finden, benötigt man eine Suchfunktion. An einem Beispiel: 1. Öffnen des Dictionary (TC: SE11) zu ABAP Dictionary siehe Workshop Skript 2. Taste <F4> für Eingabehilfe: Suchfenster erscheint. 3. Eingabe MA* <Enter> 4. Neue Suche: Button für detaillierte Selektion 5. Karteikarte Intervall: von: MAB* bis: MAO* Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -9- Kapitel 5 Kapitel 6 ABAP – Start: 1. Aufruf des ABAP-Editors: Transaktionscode: SE38 oder Easy Access Menü: Werkzeuge ABAP-Workbench Entwicklung ABAP Editor 2. Anlegen eines Programms: 1. Namenskonventionen: YTU_XX_Bezeichnung 2. Button: Anlegen 3. Titel eintragen; Typ: ausführbares Programm; Button: Sichern 4. Button: lokales Objekt 3. Im Editor: Nach dem Programmkopf folgenden Text eingeben: „write ‘ Hallo‘ “. . Es erscheint eine Fehlermeldung. „... (Punkt fehlt)“ Programm prüfen mit Zeile ändern: „write ‘ Hallo‘ .“ Prüfen. Ausführen mit Einleitung Kapitel 1 Kapitel 2 Kapitel 3 . Kapitel 4 - 10 - Kapitel 5 Kapitel 6 Online – Hilfe: Es gibt verschiedene Hilfen: • Schlüsselwortdokumentation: Taste <F1> wenn der Cursor auf einem Schlüsselwort steht • Glossar: Hilfe Glossar • SAP Bibliothek: Hilfe SAP Bibliothek, oder im Internet: http://help.sap.com Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 11 - Kapitel 5 Kapitel 6 Aufgaben: 1. Machen Sie sich mit dem SAP-System (Transaktionscodes, Online-Hilfe, Modis) und speziell mit dem ABAP-Dictionary und dem ABAP-Editor vertraut! 2. Suchen Sie im ABAP-Dictionary nach verschiedenen Datenbanken und verwenden Sie hier die Einzelwert- und die Intervallsuche! 3. Legen Sie im ABAP-Editor ein Programm mit dem Namen HELLO_SAP an (Konventionen zur Namensgebung beachten!) und lassen Sie einen beliebigen Text aus! Einleitung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 12 - Kapitel 5 Kapitel 6 Programmtypen Jedes ABAP-Programm hat einen festgelegten Typ, der seine Eigenschaften definiert. Es gibt 7 Programmtypen, die im Folgenden unterschieden werden sollen. Typ 1: Programme vom Typ 1 ermöglichen einen Start unter der Angabe des Programmnamens und heißen deshalb ausführbare Programme. Da die Definition von Ereignisblöcken nicht vorgeschrieben ist, kann der Programmierer entscheiden, auf welche Ereignisse das ausführbare Programm reagieren soll. Das einfachste ausführbare Programm enthält z.B. nur den Standardverarbeitungsblock START-OF-SELECTION. Programme vom Typ 1 werden auch Reports genannt. Kapitel 1 Programmtypen Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Typ F: Programme vom Typ F können nicht gestartet werden, da sie als Rahmenprogramme für Funktionsbausteine dienen. Durch den Aufruf aus einem laufenden ABAP-Programm wird das komplette Rahmenprogramm in den internen Modus des laufenden Programms dazugeladen. Wir bezeichnen Typ F-Programme auch als Funktionsgruppen. Funktionsbausteine dürfen nur in Funktionsgruppen programmiert werden. Außer Funktionsbausteinen können Funktionsgruppen globale Datendeklarationen und Unterprogramme enthalten, die für alle Funktionsbausteine sichtbar sind. Typ M: Programme vom Typ M können nur über Transaktionscodes gestartet werden. Typ K: Programme vom Typ K können nicht gestartet werden. Sie dienen als Rahmenprogramm für globale Klassen. Kapitel 1 Programmtypen Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Typ J: Programme vom Typ J können nicht gestartet werden. Sie dienen als Rahmenprogramm für globale Interfaces. Typ S: Programme vom Typ S können nicht gestartet werden. Sie dienen als Rahmenprogramm für Unterprogramme, die nur extern aufgerufen werden sollen. Typ I: Programme vom Typ I können nicht gestartet werden und enthalten keine aufrufbaren Verarbeitungsblöcke. Sie dienen ausschließlich der Modularisierung von ABAP-Quelltext und werden in andere ABAP-Programme eingebunden. Wir nennen Typ-I Programme IncludeProgramme, da der Programmtext in Include-Programmen über die Anweisung INCLUDE an beliebigen Stellen anderer ABAP-Programm eingefügt werden kann. Nun wissen Sie, welche Arten von Programmen ABAP kennt und wann Sie diese einzusetzen haben. Auf einige dieser Programmtypen werden wir später noch einmal zurückkommen. Kapitel 1 Programmtypen Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Werkzeuge Das zentrale Werkzeug des ABAP Workbench ist der ABAP-Editor. Um ihn zu starten, und damit ABAP-Programme anzulegen oder zu ändern, gibt es im R/3-System verschiedene Möglichkeiten. Programme im Object Navigator öffnen: ABAP-Programme öffnen Sie im Object Navigator, indem Sie diesen unter Werkzeuge Æ ABAP Workbench Æ Übersicht Æ Object Navigator starten. Im Einstiegsbild können Sie links oben ein Programm auswählen in dem Sie direkt einen Programmnamen eingeben oder sich sämtliche Programme einer bestimmten Entwicklungsklasse anzeigen lassen. Kapitel 1 Werkzeuge Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Der Object-Navigator erlaubt durch die Auswahl von Programmen Direktzugriff auf alle Einzelteile eines Programms wie z.B. Hauptprogramm, Include-Programme, Klassen oder globale Daten. Über die Auswahl eines Programmobjekts im Object-Navigator und dem Aufruf einer Pflegefunktion öffnen Sie auf der rechten Bildschirmseite direkt das passende Werkzeug, den ABAP-Editor. Vor allem haben Sie im Object-Navigator immer einen Überblick über alle zum Programm gehörigen Komponenten. Es werden sowohl Bildschirme als auch deren Benutzungsoberflächen angezeigt. Programme durch Vorwärtsnavigation öffnen: Wenn man beim Arbeiten mit einem Werkzeug ein Objekt der ABAP-Workbench auswählt, öffnet das System das Objekt mit dem zugehörigen Werkzeug. Gleiches geschieht beim Editieren von ABAP-Programmen. Diese Möglichkeit bietet sich an jeder Stelle, wo Namen von ABAPProgrammen in der ABAP-Workbench auftauchen. Kapitel 1 Werkzeuge Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Wichtige Funktionen des ABAP-Editors: (1) Programm prüfen: Wenn Sie das Editieren Ihres Codes abgeschlossen haben, sollten Sie Ihr Programm auf eventuelle Syntax-Fehler hin prüfen. Dies geschieht indem Sie auf das Symbol Prüfen klicken. Das System überprüft nun Ihren Programmcode auf Syntaxfehler und Kompatibilitätsprobleme. Sollten derartige Fehler auftreten werden sie im unteren Bereich des Bildschirms mit Korrekturvorschläge angezeigt. (2) Programm sichern und aktivieren: Der Code kann mit dem Symbol Speichern gespeichert werden und durch Aktivieren aktiviert werden. Durch das Aktivieren wird von Ihrem Programm nun eine Aktive Version erzeugt, und anschließend eine Laufzeitversion generiert. (3) Programm testen: Ausführbare Programme können getestet Kapitel 1 Werkzeuge Kapitel 2 Kapitel 3 werden. Kapitel 4 -3- Kapitel 5 Kapitel 6 (4) Programmtest mit Debugger: Um Programmodule eigenständig testen zu können verwendet man den ABAP-Debugger. Dadurch haben Sie die Möglichkeit, das Programm Zeile für Zeile auszuführen. Die Anwahl des Debuggers erfolgt im Kontextmenü des Programms über das Menü: Ausführen Æ Debugging. Sie haben durch den Debugger die Möglichkeit, das Programm Zeile für Zeile auszuführen und können es bei semantischen Fehlverhalten auch anhalten. (5) Hilfe zu ABAP: (5.1) Schlüsselwortdokumentation: Klicken Sie hierzu auf ein Schlüsselwort und drücken Sie anschließend F1. (5.2) ABAP-Beispielbibliothek: Die Ansteuerung der ABAP-Beispielbibliothek kann zum Beispiel aus der Schlüsselwortdokumentation heraus durch einen Klick auf das Bild Example-Library oder durch Anwahl über das Hilfe-Icon symbolisiert werden. Kapitel 1 Werkzeuge Kapitel 2 erfolgen. Sie ist in Kapitel aufgeteilt, die durch Buchikonen Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Diese hier vorgestellten Werkzeuge sind essentiell bei dem anfänglichen Umgang mit ABAP. Weitere Werkzeuge werden Sie in den weiteren Kapiteln kennen lernen. Kapitel 1 Werkzeuge Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Programm anlegen Das Anlegen eines ABAP-Programms erfolgt zunächst in 8 einfachen Schritten: 1. Öffnen Sie das SAP-Logon. 2. Wählen Sie als Server „SAP R/3“ aus und klicken Sie auf Logon. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 3. Melden Sie sich mit Ihrem Logon und Passwort an. Achten Sie darauf, dass bei Mandant 903 eingetragen ist. 4. Nun befinden Sie sich im Benutzermenü von SAP Easy Accsess. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 5. Wählen Sie nun im Menü Werkzeuge Æ ABAP-Workbench Æ Entwicklung Æ ABAP Editor aus. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 6. Geben Sie nun den Namen Ihres Programms an. a) Schreibweise: YTU_<log>_<name>. b) Klicken Sie nun auf Anlegen. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 7. Nun erscheinen die Programmeigenschaften. Stellen Sie folgende Eigenschaften ein: a) Titel eingeben b) Typ: ausführbares Programm c) Objektlistentyp: lokales Objekt ÆLokale Objekte sind der Entwicklungsklasse $TMP zugeordnet und sind private Objekte, die nicht in andere Systeme transportiert werden können. 8. Sichern Sie die Programmeigenschaften. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Nun ist Ihr Programm im R/3 Repository vorhanden und sie können anfangen Ihren Quelltext im Editor einzugeben. Programmaufbau: Um ein ABAP-Programm einzuleiten, verwenden Sie die Anweisungen Report oder Program. Die Funktionalität beider Anweisungen ist identisch. Nach einer dieser Anweisungen sollte der Name Ihres Programms stehen, wobei dies nicht zwingend erforderlich ist aber aus dokumentarischen Gründen nützlich. Der nächste Schritt sollte nun darin bestehen, dass Sie sämtliche Deklarationen von Selektionsbildern, programmlokalen Klassen, Interfaces und/oder globalen Datendeklarationen vornehmen. Danach folgt die Verarbeitungslogik, die aus einer Reihe von Verarbeitungsblöcken besteht. Sämtliche internen Prozeduren eines ABAP-Programms sollten als letzte Einheiten am Ende des Programms aufgelistet sein. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 Namenskonvention: Alle Objekte die Sie erstellen sollten mit Y beginnen, da Y ein reservierter Bereich für Kunden ist. Danach schließt sich der Name der Einrichtung an (in unserem Falle TU für TU-Chemnitz). Nun folgt nach einem Unterstrich Ihr Kürzel und nach einem weiteren Unterstrich der eigentlich Name des Programms. Bsp.: YTU_13_HELLOWORLD Übersichtlichkeit/Layout: Besonders bei größeren Programmen, die Sie im späteren Verlauf dieses Kurses schreiben werden, empfiehlt es sich, dass Sie Ihr Programm ausreichend mit Kommentaren versehen um spätere Korrekturen oder Anpassungen zu erleichtern und die Übersichtlichkeit zu erhöhen. Kapitel 1 Programm anlegen Kapitel 2 Kapitel 3 Kapitel 4 -7- Kapitel 5 Kapitel 6 Syntax Die Syntax von ABAP besteht im wesentlichen aus einer Vielzahl von Syntaxelementen. Die meisten Elemente sollten Ihnen aus anderen Programmiersprachen bereits bekannt sein. Das ABAP-Programm besteht aus mehreren Anweisungen, die verschiedenartig zusammengesetzt werden. Jede Anweisung beginnt mit einem Schlüsselwort, gefolgt von Parametern und endet mit einem Punkt. Syntax: Schlüsselwort [Parameter]. Beispiel: WRITE `Hallo World`. Kapitel 1 Syntax Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Um die Lesbarkeit von Programmen zu erhöhen, sollten die Schlüsselworte in Großbuchstaben geschrieben werden. ABAP besitzt keine Formateinschränkungen, daher können Anweisungen frei eingegeben werden. Allerdings gilt hier, dass Anweisungen durch mindestens ein Leerzeichen getrennt sein müssen und das ein Zeilenende ebenfalls als Leerzeichen gewertet werden. Daraus resultieren nun folgende Eingabemöglichkeiten von Anweisungen: 1. Einrücken von Anweisungen WRITE `Hallo World`. 2. Mehrere Anweisungen auf einer Zeile WRITE `Hallo`. WRITE ´World´. 3. Anweisung über mehrere Zeilen WRITE ´Hallo World´. Kapitel 1 Syntax Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Kettensätze: Mehrere aufeinander folgende Anweisungen, die den gleichen Anfang haben, können miteinander verkettet werden. Um diese Anweisungen miteinander zu verketten, schreiben Sie den für alle Anweisungen identischen Anfang nur einmal, gefolgt von einem Doppelpunkt. Danach werden die nicht identischen Teile angegeben und mit einem Komma voneinander getrennt. Der Abschluss der Anweisungskette erfolgt durch einen Punkt. Kapitel 1 Syntax Kapitel 2 *statt: WRITE 'Hallo World'. WRITE 'ist mein erstes Programm'. WRITE 'in ABAP'. *besser als Anweisungskette: WRITE: 'Hallo World ', 'ist mein erstes Programm', 'in ABAP'. *alternative Schreibweise: WRITE: 'Hallo World ', 'ist mein erstes Programm', 'in ABAP'. Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Kommentare: Kommentare kommen zum Einsatz, wenn Sie Ihren Quelltext kommentieren um somit die Lesbarkeit bei späteren Änderungen zu erhöhen. In ABAP gibt es zwei verschiedene Arten von Kommentaren. * Î gesamte Zeile wird ignoriert “ Î alle Eingaben nach “ werden ignoriert *mein ersten Programm WRITE ’Dies ist eine Ausgabe’ . “ Kommentar Damit ist der erste Komplex beendet. Sie sollten nun in der Lage sein, einfache Programme anzulegen und auszuführen. Vertiefen Sie Ihr Wissen, indem Sie die Aufgaben bearbeiten, die sich auf der folgenden Seite befinden. Sollten Fragen oder Probleme auftauchen, scheuen Sie sich nicht Ihren Tutor/Betreuer zu fragen. Kapitel 1 Syntax Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Aufgaben: 1. Legen Sie ein ABAP- Programm an. 2. Schreiben Sie ein kleines Programm, das den Text 'Meine ersten Schritte in ABAP' ausgibt. 3. Ändern Sie das Programm ab, in dem Sie den Text in zwei Teiltexte zerlegen und geben Sie diese als Kettensatz aus. 4. Fügen Sie dem obigen Programm zusätzlich zwei Kommentare an. Den ersten geben Sie auf einer separaten Zeile, den zweiten an den Quelltext anschließend aus. Kapitel 1 Syntax Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Datentypen Datenobjekte: Die physikalischen Einheiten, mit denen ABAP-Anweisungen zur Laufzeit arbeiten und deren Inhalt vom Programm während der Laufzeit adressiert und interpretiert werden kann, nennen wir programmlokale Datenobjekte. Der Zugriff auf den Inhalt der Datenobjekte erfolgt über ABAP-Anweisungen, wobei eine ständige Bindung an das aktuelle Programm vorliegt. Jedes ABAP-Datenobjekt hat bestimmte technische Eigenschaften (z.B. Datentyp, Feldlänge und Anzahl der Nachkommastellen), die zu jedem Zeitpunkt der Laufzeit eines ABAP-Programms vollständig spezifiziert sind. Die Verwendung bestimmter Datentypen richtet sich nach der Verwendung der Datenobjekte im Programm. Auch ein Bezug auf schon vorhandene Datenobjekte/Variablen mittels LIKE ist möglich. Syntax: DATA [Variablenname]([Länge]) TYPE [Datentyp] VALUE [Feldwert]. DATA [Variablenname] LIKE [Variablenname]. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Datentypen sind reine Typbeschreibungen, an denen kein Speicher hängt. Ein Datentyp charakterisiert die technischen Eigenschaften aller Datenobjekte, die diesen Typ haben. Sie können als Attribute von Datenobjekten auftreten, aber auch eigenständig definiert werden. Die Definition von eigenständigen Datentypen baut auf einem Satz von vordefinierten Datentypen auf und kann programmintern im Deklarationsteil über TYPES oder programmübergreifend im ABAPDictionary erfolgen. Eigenständige Datentypen werden zur Deklaration von Datenobjekten und zur Typüberprüfung bei generischen Operationen verwendet. Durch die Anweisung TYPES, die eine Definition von benutzerdefinierten elementaren Datentypen, beruhend auf vordefinierten elementaren Datentypen zulässt, werden sämtliche technischen Merkmale des neuen Datentyps festgeschrieben. Elementare Datentypen verwendet man zur Definition einzelner elementarer Datenobjekte. Syntax: TYPES [Variablenname]([Länge]) TYPE [Datentyp]. TYPES [neuer Typ] LIKE [Variablenname]. Im Gegensatz zu TYPE wird bei LIKE auf den Datentyp einer Variable Bezug genommen. Dies wird aber in späteren Beispielen noch näher erläutert. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Elementare Datentypen sind atomar, da sie sich aus keinen anderen Typ zusammensetzen. Dabei wird in zwei Arten von eingebauten Datentypen (DT) unterschieden: a) Datentypen mit fester Länge, die statisch bei der Definition festgelegt wird. b) Datentypen mit dynamischer Länge, die sich während der Laufzeit ändern kann. DT fester Länge: Es gibt acht in ABAP eingebaute elementare Datentypen fixer Länge. Davon gehören vier zu den zeichenartigen Typen, nämlich Zeichenfelder (c), numerische Zeichenfelder (n), Datumsfelder (d), Zeitfelder (t) und drei zu den numerischen Typen, nämlich Integer für ganze Zahlen (i), Gleitpunktzahlen (f) und gepackte Zahlen (p). Eine Sonderform stellt x dar, da es für Byte-Felder mit hexadezimaler Anzeige steht und somit nicht zu numerischen und zeichenartigen Typen zählt. Auch n hat eine Sonderrolle. Es ist kein Zahlentyp - obwohl dessen Werte reine Ziffernfolgen sind, sondern ein zeichenartiger Typ, da mit solchen Ziffernfolgen i. a. nicht gerechnet wird. Typische Beispiele für Felder des Typs n sind Konto- und Artikelnummern (sofern diese nur aus Ziffern bestehen), sowie Teilfelder von Datums- und Zeitfeldern. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Die wichtigsten Eigenschaften dieser acht Datentypen sind: Typ Kapitel 1 Bedeutung Standardlänge mögliche Länge(Bytes) Standard-Initialwert c Zeichenkette 1 1-65535 ''(Space) n NumerischeZeichenkette 1 1-65535 '0...0' d Datum(JJJJMMTT) 8 8 '00000000' t Uhrzeit(HHMMSS) 6 6 '000000' i GanzeZahl 4 4 0 f Gleitkommazahl 8 8 '0.0' p GepackteZahl 8 1-16 0 x Hexadezimalzahl 1 1-65535 X'00' Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Die Typen c, n, p und x belegen nicht immer gleich viel Speicherplatz. Es handelt sich um generische Datentypen, bei denen bei der Deklaration optional Angaben über die Länge gemacht werden können. Geschieht dies nicht, so wird die Standardlänge verwendet. Eine Änderung der Länge während der Laufzeit ist nicht möglich. - Typ c ist ein Typ für beliebige Zeichenketten mit fester Länge, wobei abschließende Leerzeichen ignoriert werden. Auch als Ersatz für den fehlenden booleschen Datentyp findet er Verwendung (Datenobjekt vom Typ c der Länge 1). Dem Datenobjekt vom Typ c wird eine Zeichenkette in einem Literal zugewiesen. - Typ n ist ein Typ für numerische Werte aber kein numerischer Datentyp und kann nur Ziffern beinhalten, die nicht zur Berechnung dienen. Für Berechnungen ist erst eine Typkonvertierung nötig. Typ n findet Anwendung bei der Wiedergabe von Bankleitzahlen, Postleitzahlen und Postfachnummern. - Typ x ist ein Datentyp beliebiger Byteketten. In einem Byte kann jedes Halbbyte von vier Bit Werte zwischen null und fünfzehn annehmen, die Hexadezimale Werte darstellen. Dem Datenobjekt vom Typ x wird ein Literal, das eine hexadezimale Zeichenfolge enthält, zugewiesen. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 - Typ d ist ein Typ für Datumsangaben, dessen Inhalt, sofern er ein gültiges Datum (z.B.20020315) darstellt, in mathematischen Ausdrücken als Datum interpretiert, mit dem Berechnungen durchgeführt werden können. Wenn Eingabefelder den Typ d haben, so wird deren Inhalt auf Korrektheit des Datums überprüft. Des Weiteren kann man auch mit dem aktuellen Datum über die Systemvariable SY-DATUM operieren. - Typ t ist ein Typ für Zeitangaben, dessen Inhalt, sofern er eine gültige Zeit (z.B.103000) darstellt, in mathematischen Ausdrücken als Zeit interpretiert, mit den Berechnungen durchgeführt werden können. Wenn Eingabefelder den Typ t haben, so wird deren Inhalt auf Korrektheit der Zeit überprüft. Des Weiteren kann man auch mit der aktuellen Zeit über SYUZEIT operieren. - Typ i hat einen Wertebereich von -2147483648 bis 2147483647, und umfasst nur ganze Zahlen. Auch alle Zwischenergebnisse sind vom Typ i abgelegt. Bei der I-Arithmetik wird gerundet und nicht abgeschnitten und ein Überlauf führt zu einem Laufzeitfehler. Typ i findet Verwendung für Zähler, Anzahlen, Indizes und Offsets sowie Zeitspannen. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 - Typ f hat einen Wertebereich von 2,2250738585072014E-308 bis 1,7976931348623157E+308, der gut 15 Dezimalziffern entspricht. Gleitpunktzahlen können im Programm nicht direkt angegeben werden, sondern es müssen Textliterale verwenden, deren Inhalt als Gleitpunktzahl interpretiert werden kann. Sie werden bei Bedarf konvertiert. Erlaubt sind Formate wie: Dezimalzahl mit oder ohne Vorzeichen, mit oder ohne Dezimalpunkt. Die Form [Mantisse]E[Exponent], wobei die Mantisse eine Dezimalzahl ist und der Exponent mit oder ohne Vorzeichen angegeben werden kann. Darüber hinaus sind Leerzeichen vor oder hinter der Zahl erlaubt. (Beispiele für Textliterale mit "Gleitpunktzahlen": '1', '-12.34567', '-765E04', '1234E5', '+12E+34', '+12.3E-4', '1E160') - Typ p hat einen Wertebereich von 1 bis 16 Bytes, der von der Länge sowie von der Anzahl der Dezimalstellen abhängt. In jedes Byte werden dabei 2 Dezimalziffern gepackt, nur das letzte Byte besteht aus einer Dezimalziffer und dem Vorzeichen. Die Grenze liegt hier bei 14 Nachkommastellen. Hilfsfelder für Zwischenergebnisse können bis zu 31 Dezimalziffern aufnehmen. Will man verhindern, dass alle Zahlen als ganzen Zahlen aufgefasst werden und auch alle Zwischenergebnisse zur nächsten ganzen Zahl gerundet werden, so muss man das Programmattribut "Festpunktarithmetik" setzen. Die Verwendung liegt im Rechnen mit Größen wie Längen, Gewichte und Geldbeträge. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -7- Kapitel 5 Kapitel 6 DT variabler Länge: Es gibt zwei in ABAP eingebaute elementare Datentypen variabler Länge. Dies sind STRING für Zeichenfolgen und XSTRING für Bytefolgen. Die Länge solcher Datenobjekte kann, im Gegensatz zu Datentypen fester Länge, während der Laufzeit verändert werden. - Der Typ STRING ist in der Lage, beliebig große Zeichenketten aufzunehmen. String ist eine dynamische Entsprechung des Typs c, weshalb ihm die gleiche Zeichenkette dynamisch zugewiesen werden kann. - Der Typ XSTRING ist eine dynamische Entsprechung des Typs x und kann beliebig lange Bitfolgen aufnehmen. Die Länge der Bitfolge wird dabei dynamisch auf ein Byte festgelegt und kann immer wieder verändert werden. Syntax : DATA [Variablenname] TYPE [Datentyp] VALUE [Feldwert]. Anstatt einer Variablen ist bei c, n, p, x auch [Variable]([Länge]) möglich, VALUE ist optional. Wird TYPE weggelassen ist der Defaulttype c. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 -8- Kapitel 5 Kapitel 6 Datentypen des Data-Dictionary: Es gibt auch im ABAP-Dictionary einen Satz eingebauter Datentypen, die Grundlage für weitere Typen darstellen. Die Datentypen des Dictionarys sind wesentlich umfangreicher, als die ABAPDatentypen, da sie mit den externen Datentypen der von SAP unterstützten Datenbanktabellen verträglich sein müssen. Eine direkte Verwendung der Datentypen des ABAP-Dictionarys ist nicht möglich, aber die Definition eigener Datentypen im ABAP-Dictionary, die dann im ABAP-Programm verwendet werden können. Einige ausgewählte Beispiele der Tabelle der Dictionary-Typen mit ihrer ABAP-Entsprechung: Dictionary-Typ Kapitel 1 Datentypen Kapitel 2 Bedeutung ABAP-Typ CHAR Character c(m) CLNT Mandant c(3) CURR Währungsfeld p((m+1)/2) LANG Sprache c(3) QUAN Menge p((m+1)/2) UNIT Einheit c(m) Kapitel 3 Kapitel 4 -9- Kapitel 5 Kapitel 6 Weiterführende Informationen hierzu finden sich in der SAP-Onlinehilfe. Es folgt ein kurzes Beispiel, dass die Verwendung von Datentypen sowie die Deklaration von Datenobjekten demonstriert. REPORT YTU_01_DT. DATA pi TYPE F VALUE '3.1415'. *Deklaration einer Variablen DATA: pi2 TYPE F VALUE '3.1415', eps TYPE F VALUE '0.001'. *Deklaration von zwei Variablen DATA: string(4) TYPE C VALUE 'ABAP', number TYPE p DECIMALS 2. * analog werden andere DT behandelt number WRITE: WRITE: WRITE: WRITE: Kapitel 1 = / / / / '-123.99'. 'Zahl Pi : ',pi. 'Zahl Eps : ',eps. 'String der Länge 4: ',string. 'Fehlbetrag : ',number. Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 10 - Kapitel 5 Kapitel 6 Konstanten: Neben den mit DATA deklarierten Datenobjekten sind auch Deklarationen von Konstanten über CONSTANTS möglich. Es handelt sich um benannte Datenobjekte, deren Wert über die gesamte Laufzeit festliegt. Deshalb ist auch der Zusatz VALUE nicht optional. Daher sind nur statische, elementare Datenobjekte als Konstanten deklarierbar. Es ist möglich, an allen Stellen im Programm den jeweiligen Wert für die Konstante zu schreiben. Da dieses Vorgehen häufig zu Fehlern führt und das Programm dadurch zusätzlich an Übersichtlichkeit verliert, was Probleme bei nachträglichen Anpassungen verursacht, werden Konstanten häufig als unveränderbare Felder mit symbolischen Namen meist an einer zentralen Stelle vereinbart. Durch die Deklaration von Konstanten für häufig im Programm verwendete Werte wird außerdem eine erhöhte Lesbarkeit des Programms gewährleistet. Eine erneute Deklaration derselben Konstante ist hierbei unzulässig. Typische Anwendungsbereiche sind der Umrechnungskurs zwischen zwei Währungen, Steuercodes und auch feste Formate wie Anzahl der Zeichen einer Zeile. Auch die Deklaration strukturierter Konstanten ist möglich. Die geschieht wie bei Variablen durch BEGIN OF und END OF. Auf die Deklaration von Strukturen wird später noch genauer eingegangen. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 11 - Kapitel 5 Kapitel 6 Syntax: gängige Form: CONSTANTS [Konstante] TYPE [Datentyp] {DECIMALS [Dezimalstellen]} VALUE [Feldwert]. für eine Konstante die auf ihren Initalwert gesetzt wird: CONSTANTS [Konstante] TYPE [Datentyp] VALUE IS INITIAL. für eine strukturierte Konstante: CONSTANTS: BEGIN OF [Strukturname], [Deklarationen]. END OF [Strukturname]. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 12 - Kapitel 5 Kapitel 6 REPORT YTU_01_Konstanten. CONSTANTS Umrechnung TYPE p DECIMALS 2 VALUE '1.97'. *Deklaration einer Konstanten CONSTANTS: BEGIN OF Umrechnungskurs, Land(3) TYPE c VALUE 'USA', Ankauf TYPE p DECIMALS 2 VALUE '1.10', Verkauf TYPE p DECIMALS 2 VALUE '1.25', Datum TYPE d VALUE 20020317, END OF Umrechnungskurs. *Deklaration einer strukturierten Konstanten WRITE: / 'Umrechnungskurs DM - Euro : ',Umrechnung. WRITE: / 'Dollar- Euro Umrechnung : ', Umrechnungskurs-Land, 'Ankauf :',Umrechnungskurs-Ankauf, 'Verkauf :',Umrechnungskurs-Verkauf. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 13 - Kapitel 5 Kapitel 6 Systemfelder: Es gibt in ABAP eine Anzahl vordefinierter Systemfelder, die immer vorhanden und kontextunabhängig sind. Sie sind wichtig im Zusammenhang mit dem System und sollten deshalb nur abgerufen aber nicht verändert werden. Falls eine Veränderung zur Systemsteuerung unumgänglich ist, sollten Änderungen nur mit aller größter Vorsicht geschehen, da das gesamte Programm zum Absturz gebracht werden kann. Diese Datentypen sind im ABAP-Dictionary definiert und können aus einer Struktur Namens SY, die während der Laufzeit erzeugt wurde, abgerufen werden. Viele der Komponenten sind aber nur für die interne Verwendung vorgesehen. Syntax: SY-[Feld] REPORT YTU_01_DT. WRITE: / 'aktuelles Datum: ',SY-DATUM. WRITE: / 'aktueller Nutzer: ',SY-UNAME. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 14 - Kapitel 5 Kapitel 6 Systemfeld SY-MANDANT SY-UNAME SY-DATUM SY-UZEIT SY-ZONLO SY-INDEX SY-TABIX SY-REPID SY-ULINE SY-VLINE Kapitel 1 Datentypen Kapitel 2 Bedeutung aktuelle Mandantennummer aktueller Nutzer Datum des Applikationsservers Zeit des Applikationsservers Zeitzone des Benutzers Anzahl der bisherigen Schleifendurchläufe (DO, WHILE) zuletzt angesprochene Zeile einer internen Tabelle Name des aktuellen ABAP- Programms horizontaler Strich der Länge 255 vertikaler Strich für Listenausgaben Kapitel 3 Kapitel 4 - 15 - Kapitel 5 Kapitel 6 Aufgaben: 1. Schreiben Sie ein Programm, mit dessen Hilfe der Satz: "Es gibt 8 elementare Datentypen fixer Länge in ABAP." ausgegeben wird. Verwenden Sie zur Umsetzung mindestens drei verschiedene Datentypen. 2. Schreiben Sie ein Programm, das die Aussage "acht durch drei = 8 / 3" ausgibt. Verwenden Sie dabei eigene Typdefinitionen und LIKE. 3. Geben Sie das aktuelle Datum und die aktuelle Uhrzeit aus. 4. Geben Sie die Zahl Pi mit zwei Nachkommastellen aus. Deklarieren Sie diese Zahl als Konstante. Kapitel 1 Datentypen Kapitel 2 Kapitel 3 Kapitel 4 - 16 - Kapitel 5 Kapitel 6 Wertzuweisung Wenn der Feldinhalt von Variablen geändert werden soll, werden Wertzuweisungen eingesetzt. Hierzu wird die Anweisung MOVE bzw. der Zuweisungsoperator "=" verwendet. Die meisten anderen Wertzuweisungen werden intern auf die Semantik der Anweisung MOVE zurückgeführt. Durch die Anweisung CLEAR erfolgt eine typgerechte Rücksetzung auf den Initialwert. Syntax: MOVE [Quelldatenobjekt] TO [Zieldatenobjekt]. oder [Zieldatenobjekt] = [Quelldatenobjekt]. Auch Mehrfachzuweisungen ([f4] = [f3] = [f2] = [f1].) sind möglich, die ABAP von rechts nach links verarbeitet (MOVE [f1] TO [f2]. MOVE [f2] TO [f3]. MOVE [f3] TO [f4].). In der MOVE-Anweisung können die Namen von Quell- und Zielfelder nicht dynamisch als Inhalte anderer Felder angegeben werden. Falls dies erforderlich ist, müssen Feldsymbole verwendet werden. Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Folgende Fälle können bei Wertzuweisungen auftreten: 1. Die Datenobjekte sind vollständig kompatibel, weswegen der Inhalt des Quellfelds ohne weitere Manipulation Byte für Byte in das Zielfeld übertragen wird. 2. Die Datenobjekte sind nicht kompatibel, wobei sie nur eine unterschiedliche Länge haben müssen. Der Inhalt des Quellfelds wird so konvertiert, dass er zum Datentyp vom Zielfeld passt und bei Erfolg erst dann übertragen wird. Ist dies nicht möglich, bricht das Programm ab. REPORT YTU_01_zuweisung. DATA: datum(10) TYPE c, nummer TYPE p DECIMALS 2, zahl TYPE i. datum = 1111. MOVE '5.75' TO nummer. zahl = nummer. * Nach diesen Zuweisungen haben die Felder *datum, nummer, und zahl die Werte '1111 ', 5,75 und 6. WRITE: / datum, nummer, zahl. Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Werte mit WRITE TO zuweisen: Neben der Anweisung MOVE gibt es die Anweisung WRITE TO, die den Inhalt des Quellfelds in ein Feld vom Typ c konvertiert. Syntax: WRITE [Datenobjekt1] TO [Datenobjekt2] {[Operation]}. Diese Anweisung konvertiert den Inhalt eines beliebigen Datenobjekts nach Typ c und überträgt die resultierende Zeichenkette in eine Variable [Datenobjekt2]. Der Inhalt von [Datenobjekt1] bleibt unverändert. Die Variable [Datenobjekt2] wird unabhängig von ihrem tatsächlichen Typ immer als Character-Feld interpretiert. Es findet keine typgerechte Umsetzung statt. Warnung der Syntaxprüfung!: Es ist möglich, dass aus solch einer Warnung in zukünftigen Releases ein echter Syntax- bzw. Laufzeitfehler wird. Die Anweisung WRITE TO berücksichtigt auch die Vorgaben im Benutzerstammsatz. Weiterhin können außer UNDER und NO-GAP sämtliche Aufbereitungsoptionen genutzt werden. Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Variablen auf ihren Initialwert setzen: Variablen werden bei ihrer Vereinbarung initialisiert. Um eine Variable zu einem späteren Zeitpunkt auf ihren typgerechten Initialwert (nicht VALUE-Wert) zu setzen verwendet man die Anweisung: Syntax: CLEAR [f]. Wirkung auf Datenobjekte unterschiedlicher Datentypen: 1. elementare ABAP-Typen: Es werden die Werte der Variablen auf die Initialwerte, die in der Tabelle unter elementare Datentypen aufgeführt sind, gesetzt. 2. Referenzen: Es wird der Inhalt einer Referenzvariablen auf ihren Initialwert, bei dem die Referenz auf kein Objekt zeigt (NULL-Zeiger) gesetzt. 3. Strukturen: Es werden die elementaren Komponenten einer Struktur auf ihre typgerechten Initialwerte zurückgesetzt. 4. interne Tabellen: Es werden sämtliche Zeilen einer internen Tabelle gelöscht. Beachte: Interne Tabellen können nicht mit der Anweisung CLEAR zurückgesetzt werden! (Mehr dazu später.) Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 REPORT YTU_01_zuweisung. DATA nummer TYPE i VALUE '10'. WRITE nummer. CLEAR nummer. WRITE / nummer. Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Aufgabe: Spielen Sie ein wenig mit den Aufgaben aus den vorherigen Abschnitten und weisen Sie den Variablen verschiedene Werte zu. Kapitel 1 Wertzuweisung Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 Kontrollstrukturen Die Strukturierung in ABAP ist im Wesentlichen wie in allen anderen Programmiersprachen aufgebaut. 1. Sequenzen 2. Verzweigungen 3. Schleifen Bei den Bedingungen in den Schleifen und Verzweigungen handelt es sich häufig um logische Ausdrücke. Aus diesem Grund wird im weiteren auf logische Ausdrücke, Verzweigungen und Schleifen eingegangen. Sequenzen sind aus Trivialitätsgründen hier kein Thema. Zu den Schleifen gehören SELECT und LOOP. SELECT ist eine OpenSQL-Anweisung, und wird im Themenbereich „Interne Tabellen“ beschrieben. Gleiches gilt für die LOOP-Anweisung. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Sequenz Schleife Verzweigung Da ABAP nicht über einen booleschen Datentyp verfügt, können nur logische Ausdrücke zur Formulierung von Bedingungen in ABAP-Kontrollstrukturen verwendet werden. Der logische Ausdruck liefert beim Vergleich zweier Datenobjekte über einen Vergleichsoperator als Ergebnis [wahr] oder [falsch]. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Logische Ausdrücke: Arithmetische Vergleichsoperatoren: Zum Vergleich zwischen zwei Datenobjekten werden arithmetische Vergleichsoperatoren verwendet. Symboloperator alternativ Kapitel 1 Bedeutung = EQ gleich (identisch) <> NE ungleich (nicht gleich) < LT kleiner <= LE kleiner gleich > GT größer >= GE größer gleich Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Logische (boolsche) Operatoren: Um mehrere logische Ausdrücke zu einem logischen Ausdruck zu verknüpfen werden logische Operatoren verwendet. Operator Bedeutung AND logisches UND OR logisches ODER NOT logisches NICHT Durch Klammerung kann die Auswertungsreihenfolge festgelegt werden. Die Standardreihenfolge ist NOT - AND - OR. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Vergleich kompatibler elementarer Datenobjekte: Beim Vergleich elementarer Operanden ist keine Typkonvertierung nötig. Felder des Typs (i, f, p, n) werden gemäß ihres Zahlenwertes verglichen. Der Vergleich zeichenartiger Felder erfolgt stets von links nach rechts, wobei das erste verschiedene Zeichen entscheidet. Typ Beispiel Bedeutung c 'a' < 'b' Vergleich gemäß des zugrundeliegenden Zeichencodes d '20000101' > '19991231' die jüngere Datumsangabe ist größer als die ältere t '200000' > '140000' spätere Zeitangaben sind größer als die früheren x Vergleich bezüglich der Bytewerte Warnung bei Vergleichsausdrücken: sind a, b, c vom Typ f dann ist der Vergleichsausdruck (a = b) AND (b = c) immer falsch, da bitweise verglichen wird. Eine Übereinstimmung der Bitmuster liegt nur durch Zufall vor. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 Lösung über den Betrag des Differenzausdrucks und Vergleich mit einem Epsilonwert: (ABS (a - b) LE epsilon) AND (ABS (b - c) < = epsilon) ABS entspricht dem Betrag einer Zahl (jedes Zahlenformat) und Epsilon ist 0.001 vom Typ f. (Achtung: Beispiel ist theoretischer Natur um so viele Vergleichsoperatoren wie möglich zu präsentieren!) REPORT YTU_01_Vergleich. DATA: a TYPE i VALUE 2, b TYPE i VALUE 2, c TYPE i VALUE 2. a = 5. b = 6. c = 8. *(es gelten die Rechenregeln der Mathematik) ((a "kleiner- und größer als Zeichen" b) OR (b LT c)) AND (NOT (a "kleiner als" 10 )). *((a ungleich b) ODER (b kleiner c)) UND (a NICHT kleiner 10) *das Ergebnis ist [wahr] Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 Vergleich inkompatibler elementarer Datenobjekte: Datenobjekte müssen erst konvertiert werden, wenn sie inkompatibel sind, da sonst keine Zuweisungen möglich sind. Bei Datenobjekten mit gleichen Datentypen aber unterschiedlicher Länge wird der kürzere Operand vor dem Vergleich auf die Länge des längsten Operanden konvertiert. Kapitel 1 Typ Bedeutung Konvertierung p gepackte Zahl Vergleich des Zahlenwertes und deshalb Konvertierung unnötig c Textfeld von rechts mit Leerzeichen aufgefüllt n numerischer Text von links mit Nullen aufgefüllt x Hexadezimalfeld von rechts mit hexadezimalen Nullen aufgefüllt Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -7- Kapitel 5 Kapitel 6 Bei Operanden mit unterschiedlichen Datentypen werden Typkonvertierungen nach folgender Hierarchie durchgeführt. Typ Bedeutung Konvertierung zu i, p, f numerisches Feld numerischer Typ, wobei f hierarchisch höher als p, der höher als i ist. d, t Datums-, Zeitfeld in anderen Typ (numerisch/zeichenartig), mit dem verglichen wird c, x Text-, Hexadezimalfeld Typ x wird in Typ c konvertiert c, n Text-, numerisches Feld beide Operanden werden in Typ p konvertiert Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -8- Kapitel 5 Kapitel 6 Vergleich von Referenzvariablen: Referenzvariablen sind nur gleich, wenn sie auf das selbe Objekt zeigen. Die Größe der Referenzvariablen ist intern definiert. Vergleich zwischen Strukturen: In ABAP ist der Vergleich zwischen Strukturen oder von Strukturen mit elementaren Feldern zulässig. Kompatible Strukturen werden dabei komponentenweise verglichen. Die erste ungleiche Komponente entscheidet, welche Struktur größer ist. Vergleich von internen Tabellen: Interne Tabellen können ebenfalls miteinander verglichen werden. Hierzu werden sie Zeile für Zeile und Komponente für Komponente verglichen. Bei anderen Operatoren als den Gleichheitsoperator gibt der Vergleich das erste ungleiche Komponentenpaar aus. Sonstige Prüfungen: Neben den bereits erwähnten Operatoren existieren in ABAP noch weitere Operatoren zur Überprüfung. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 -9- Kapitel 5 Kapitel 6 Operator Bedeutung IS INITIAL ob ein Datenobjekt seinen typgerechten Initialwert enthält IS ASSIGNED ob einem Feldsymbol ein Datenobjekt zugewiesen ist IS [SUPPLIED/ REQUESTED] ob ein Formalparameter versorgt/abgefragt wird BETWEEN [Wert1] AND [Wert2] ob ein Datenobjekt im gewünschten Intervall liegt IN ob der Inhalt eines Datenobjektes die Bedingungen der Selektionstabelle enthält REPORT YTU_MZ_Vergleich. DATA a TYPE i VALUE 2. a = 5. a BETWEEN 0 AND 4. *das Ergebnis ist [falsch] Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 10 - Kapitel 5 Kapitel 6 Verzweigungen: Um Anweisungen nur unter bestimmten Bedingungen ausführen zu können, existieren in ABAP die Kontrollstrukturen IF und CASE. Selektion über IF: Die Bedingungen innerhalb der Anweisungsfolge werden als logische Ausdrücke formuliert. Ist der logische Ausdruck war, so wird der folgende Anweisungsblock abgearbeitet. Anschließend erfolgt ein Sprung zu ENDIF, ohne die weiteren Bedingungen zu betrachten. Ist der logische Ausdruck falsch, so wird der nächste logische Ausdruck überprüft und analog verfahren. Wenn alle Bedingungen nicht erfüllt werden, so erfolgt die Abarbeitung des Anweisungsblocks hinter ELSE. Deshalb sind beliebig viele ELSEIF-Anweisungen möglich, aber nur ein ELSE. Es ist nur die Ausführung eines Anweisungsblocks innerhalb der Verzweigung möglich, die Kontrollstruktur ist aber beliebig oft schachtelbar. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 11 - Kapitel 5 Kapitel 6 Selektion über CASE: Anstelle einer Bedingung erfolgt eine Verzweigung über den Vergleich eines Datenobjektes mit einer Ausprägung (z.B. ob eine Variable einen bestimmten Wert hat). Ist das Ergebnis des Vergleichs wahr, so werden die Anweisungen hinter dem Vergleich (WHEN) ausgeführt. Anschließend erfolgt ein Sprung zu ENDCASE, ohne die weitere Vergleiche durchzuführen. Ist das Ergebnis des Vergleichs falsch, so wird der nächste Vergleich durchgeführt und analog verfahren. Ist keiner der Vergleiche wahr, so erfolgt die Abarbeitung des Anweisungsblocks hinter WHEN OTHERS. Deshalb sind beliebig viele WHEN-Anweisungen möglich, aber nur ein WHEN OTHERS. Es ist nur die Ausführung eines Anweisungsblocks innerhalb der Verzweigung möglich, die Kontrollstruktur ist aber beliebig oft schachtelbar. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 12 - Kapitel 5 Kapitel 6 Syntax IF: IF logischer Ausdruck. [Anweisungen.]. {ELSEIF logischer Ausdruck. [Anweisungen.].} {ELSEIF logischer Ausdruck. [Anweisungen.].} {ELSE. [Anweisungen.].} ENDIF. Kapitel 1 Syntax CASE: CASE Datenobjekt. [Anweisungen.]. {WHEN Ausprägung1 [or ...]. [Anweisungen.].} {WHEN Ausprägung2 [or ...]. [Anweisungen.].} {WHEN OTHERS. [Anweisungen.].} ENDCASE. Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 13 - Kapitel 5 Kapitel 6 REPORT YTU_01_Verzweigung. DATA i TYPE i VALUE 2. i = 5. *Beginn der IF- Verzweigung, die feststellt *ob i größer/ kleiner/ gleich einem Wert ist. IF i > 5. WRITE: / 'i ist größer als 5'. ELSEIF i = 5. WRITE: / 'i ist gleich 5'. ELSEIF i > 2. * dieses ELSEIF wird nicht mehr berücksichtigt WRITE: / 'i größer als 2'. ELSE. WRITE: / 'i ist kleiner 5'. ENDIF. *… Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 14 - Kapitel 5 Kapitel 6 *… *Beginn der CASE- Verzweigung, *die das selbe Ergebnis wie die IF- Verzweigung liefert CASE i. WHEN '6' OR '7' OR '8' OR '9' OR'10'. WRITE: / 'i ist größer als 5'. WHEN '5'. WRITE: / 'i ist gleich 5'. WHEN '5'. * dieses WHEN wird nicht mehr berücksichtigt, *da sonst zwei mal 'i ist gleich 5 stehen müsste WRITE: / 'i ist gleich 5'. WHEN OTHERS. WRITE: / 'i ist kleiner 5'. ENDCASE. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 15 - Kapitel 5 Kapitel 6 Schleifen: Schleifen ermöglichen es, Anweisungen wiederholt auszuführen, i. a. mit veränderten Parametern. Man unterscheidet bedingte und unbedingte Schleifen. Damit Schleifen auch beendet werden, müssen sie einen Test enthalten, der entscheidet, ob die Schleife ein weiteres Mal durchlaufen oder das Programm nach der Schleife fortgesetzt wird. Fehlt dieser Test oder ist er fehlerhaft, bleibt der Programmlauf in dieser Schleife hängen, das Programm kommt nie zum Ende und kann nur von außen gewaltsam beendet werden. Hier ist also besondere Aufmerksamkeit geboten. Steht die Abbruchbedingung am Anfang der Schleife, so handelt es sich um eine abweisende Schleife, die unter Umständen gar nicht durchlaufen wird. Wird die Schleife somit mindestens einmal durchlaufen, weil der Test der Abbruchbedingung erst am Ende erfolgt, handelt es sich um eine nicht abweisende Schleife. SY-INDEX enthält die Anzahl der Schleifendurchläufe inklusive des aktuellen Durchlaufs. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 16 - Kapitel 5 Kapitel 6 Bedingte Schleifen: Die Anweisungen innerhalb der Schleife werden so lange abgearbeitet, bis die Bedingung nicht mehr erfüllt ist. Es handelt sich um eine abweisende Schleife. Syntax: WHILE Abbruchbedingung. [Anweisungen.]. ENDWHILE. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 17 - Kapitel 5 Kapitel 6 Nicht bedingte Schleifen: Die Anweisungen innerhalb der Schleife werden so lange abgearbeitet, bis die Anzahl der vordefinierten Durchläufe erreicht ist. Dies entspricht der Schleifenbildung wie FOR in C. Wenn die Schleife keine Anzahl vordefinierter Durchläufe hat, sondern über die Anweisung EXIT verlassen wird, handelt es sich um eine abweisende Schleife. Die Anweisungen werden bis dorthin abgearbeitet. Syntax: DO [n TIMES]. [Anweisungen.]. ENDDO. Ist n Null oder negativ wird die Schleife nicht durchlaufen! Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 18 - Kapitel 5 Kapitel 6 REPORT YTU_MZ_Schleife. DATA: i TYPE i VALUE 2, a TYPE i VALUE 2. a = 0. i = 1. *Beginn der While- Schleife, die die Nummer jedes ihrer *Schleifendurchläufe ausgibt. WHILE i "kleiner als"= 10. a = a + 1. WRITE: / 'Schleifendurchlauf Nr.: ',a. i = i +1. ENDWHILE. *Beginn der Do- Schleife, die das selbe Ergebnis *wie die While- Schleife liefert DO 10 TIMES. a = a + 1. WRITE: / 'Schleifendurchlauf Nr.: ',a. ENDDO. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 19 - Kapitel 5 Kapitel 6 Schleifensteuerung: In ABAP gibt es verschiedene Abbruchanweisungen zum Verlassen einer Schleife. Diese sind zur Realisierung nichtabweisender Schleifen, vorzeitigem Verlassen von Schleifen oder Abkürzen des Schleifendurchlaufs bei bestimmten Ereignissen nötig. Häufig erfolgt eine Einbindung innerhalb einer bedingten Verzweigung. 'Regulärer' Schleifenabbruch: Ein vollständiger Abbruch kann nach einer im voraus bekannten Anzahl von Schleifendurchläufen erfolgen, die in der Variable SY-INDEX gespeichert werden. Totaler Blockabbruch: Es kommt zu einem vollständigen Abbruch der aktuellen Schleife ohne Bedingung. Es erfolgt ein Sprung zum Schlüsselwort ENDDO oder ENDWHILE. Der Code wird ab dieser Stelle weiterbearbeitet. Ein totaler Blockabbruch wird mit dem Schlüsselwort EXIT erzwungen. Nicht bedingter Abbruch eines Schleifendurchlaufs: Nach dieser Anweisung CONTINUE werden die übrigen Anweisungen des aktuellen Anweisungsblocks übersprungen und der nächste Schleifendurchlauf wird ausgeführt. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 20 - Kapitel 5 Kapitel 6 Totaler Blockabbruch Kapitel 1 Nicht bedingter Abbruch eines Schleifendurchlaufs Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 21 - Kapitel 5 Kapitel 6 Bedingter Abbruch eines Schleifendurchlaufs: Nach dieser Anweisung werden die übrigen Anweisungen des aktuellen Anweisungsblocks übersprungen, wenn die Abbruchbedingung nicht erfüllt ist und der nächste Schleifendurchlauf wird ausgeführt. Syntax: CHECK Abbruchbedingung. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 22 - Kapitel 5 Kapitel 6 REPORT YTU_MZ_Schleifensteuerung. DATA: i TYPE i VALUE 2, a TYPE i VALUE 2. a = 0. i = 1. i = SY-INDEX. DO. IF i > 5. *Alternativ: DO 5 TIMES. exit. *Abbruch der Summierung nach 5 Werten endif. i = i + 1. a = a + 1. WRITE: / 'Schleifendurchlauf Nr.: ',a. ENDDO. *… Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 23 - Kapitel 5 Kapitel 6 *… *gleiches Ergebnis mit CHECK DO 10 TIMES. CHECK a BETWEEN 0 AND 4. a = a + 1. WRITE: / 'Schleifendurchlauf Nr.: ',a. ENDDO. *gleiches Ergebnis mit CONTINUE DO 10 TIMES. IF a > 4. CONTINUE. ENDIF. a = a + 1. WRITE: / 'Schleifendurchlauf Nr.: ',a. ENDDO. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 24 - Kapitel 5 Kapitel 6 Aufgaben: 1. Schreiben Sie ein Programm, das zum aktuellem Datum die Jahreszeit ermittelt. Hinweis: Gehen Sie vereinfachend davon aus, dass Dezember, Januar und Februar zum Winter, März, April und Mai zum Frühling, Juni, Juli und August zum Sommer und September, Oktober und November zum Herbst gehören. a) Realisieren Sie die Aufgabe unter zu Hilfenahme einer CASE-Verzweigung. b) Realisieren Sie die Aufgabe unter zu Hilfenahme einer IF-Verzweigung. Es sollen nicht mehr als sechs logische Ausdrücke verwendet werden 2. Schreiben Sie ein Programm, das bei Eingabe der Wochentagsnummer die Ausgabe des dazugehörigen Tages als Text realisiert. Fassen Sie Samstag und Sonntag zu Wochenende zusammen. a) Realisieren Sie die Aufgabe unter zu Hilfenahme einer CASE-Verzweigung. b) Realisieren Sie die Aufgabe unter zu Hilfenahme einer IF-Verzweigung. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 25 - Kapitel 5 Kapitel 6 3. Schreiben Sie ein Programm, das die Entwicklung einer festverzinslichen Geldanlage bis zur Verdopplung des Guthabens ausgibt. Es soll die Eingabe des Guthabens und eines festen Zinssatzes interaktiv erfolgen. a) Realisieren Sie die Aufgabe unter zu Hilfenahme einer WHILE-Schleife. b) Realisieren Sie die Aufgabe unter zu Hilfenahme einer DO-Schleife 4. Ermitteln Sie die Primzahlen von 1 bis 1000 durch Divisionsrest. Verwenden Sie sowohl WHILE- als auch DO-Schleifen. Kapitel 1 Kontrollstrukturen Kapitel 2 Kapitel 3 Kapitel 4 - 26 - Kapitel 5 Kapitel 6 Komplexe Strukturen Komplexe Typen sind zusammengesetzte Typen. Sie können beliebig aus elementaren Typen oder aus anderen komplexen Typen aufgebaut werden. Unter einem Namen werden semantisch zusammengehörigen Datenmengen verwaltet, die logische Einheiten bilden. Dabei kann auf einzelne Komponenten oder den gesamten Typ zugegriffen werden und auch die Übergabe an Prozeduren als ein einziges Objekt erfolgen. Sie müssen aber explizit (entweder in ABAPProgrammen selbst oder im ABAP-Dictionary) definiert werden. Hierbei wird zwischen strukturierten Typen (auch Feldleisten genannt) und tabellenartigen Typen unterschieden. Strukturierte Typen: Strukturen können Komponenten beliebigen Typs enthalten. Weil sie Komponenten beliebigen Typs enthalten können, sind auch Unterstrukturen möglich (geschachtelte Strukturen) und Tabellen als Komponenten in Strukturen (tiefe Strukturen). Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Erstellung von Strukturen: In komplexen Datentypen ist auch die Modellierung komplexer Datenobjekte erlaubt. Aggregationen von Feldern, Strukturen und internen Tabellen können in einer Deklaration zusammengefasst werden. Die Semantik für komplexe Datenobjekte ergibt sich dabei in natürlicher Weise durch rekursive Rückführung auf die entsprechenden Elementaroperationen. Hierbei sind zwei Strukturen gleich, wenn sie komponentenweise typgerecht identisch sind. Eine Struktur ist kleiner als eine andere, wenn sie in der vorgegebenen Komponentenordnung die erste kleinere Komponente enthält. Zwei Strukturen, die zwar in der Abfolge ihrer Elementarkomponenten übereinstimmen, die sich aber in der Zusammenfassung dieser Komponenten zu Unterstrukturen unterscheiden, sind nicht kompatibel. Syntax: DATA: BEGIN OF [Struktur], [Felder/ Strukturen/ interne Tabellen], END OF [Struktur]. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 REPORT YTU_MZ_DT. DATA: BEGIN OF Materialstammsatz, Artikelnr TYPE i, Artikelname(30) TYPE c, Lagerort(20), Regalstandort(10), vorhandeneMenge TYPE i, Nachlieferdatum TYPE d, END OF Materialstammsatz. Es handelt sich hierbei um eine Reihe von Vereinbarungen, was mit dem Doppelpunkt hinter DATA und den Kommata nach jeder Anweisung dargestellt wird. Deshalb ist auch die Schachtelung von Strukturen durch den Bezug auf eine bekannte Struktur des Programms oder des ABAP-Dictionarys möglich. Die Realisierung erfolgt über den LIKE bzw. TYPE-Zusatz einer Komponente der Struktur. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Arbeiten mit Strukturen: Der Zugriff erfolgt über die Felder der Struktur oder insgesamt über die Struktur, wobei sich die Elemente wie Einzelfelder verhalten. Der Name der Struktur wird durch einen Bindestrich abgetrennt und vor den Einzelfeldnamen geschrieben: Syntax: [Struktur]-[Feld]. *fuellen der vereinbarten Struktur Materialstammsatz-Artikelnr = 123. Materialstammsatz-Artikelname = 'Welle'. Materialstammsatz-Lagerort = 'Lager-A'. Materialstammsatz-Regalstandort = 'AX-234'. Materialstammsatz-vorhandeneMenge = 12. Materialstammsatz-Nachlieferdatum = '20020401'. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Zulässige Operationen: Ausgabe als Zeichenkette (WRITE) komponentenweise Zuweisung (MOVE) kopieren zwischen Strukturen gleicher Struktur (MOVE-CORRESPONDING) logische Ausdrücke (IF, CHECK, WHILE) Sortierung (SORT) und Gruppenwechselverarbeitung (AT NEW / AT END OF, ON CHANGE OF) komponentenweises Rücksetzen (CLEAR) Parameterübergabe (FORM / PERFORM, FUNCTION / CALL FUNCTION) dynamische Adressierung (ASSIGN) Aus- und Einlagerung (EXPORT / IMPORT) Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -5- Kapitel 5 Kapitel 6 *ausgeben der vereinbarten Struktur WRITE / Materialstammsatz. *Ausgabe als Zeichenkette WRITE: / Materialstammsatz-Artikelnr, Materialstammsatz-Artikelname, Materialstammsatz-Lagerort, Materialstammsatz-Regalstandort, Materialstammsatz-vorhandeneMenge, Materialstammsatz-Nachlieferdatum DD/MM/YYYY. *korrekte Ausgabe Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -6- Kapitel 5 Kapitel 6 Strukturkomponenten-Selektor: Eine besonders wichtige Eigenschaft ist die Möglichkeit, sich auf eine Datenbanktabelle des SAP-Systems zu beziehen. Eine Datenbanktabelle stellt im ABAP-Dictionary einen strukturierten Typ dar. Er entspricht in seinen Komponenten den Spalten der Datenbanktabelle, weswegen Strukturen für Daten erzeugt werden können. Syntax: DATA [Struktur] TYPE [Datenbanktabelle]. *Auch hier erfolgt das Ansprechen einzelner Komponenten mit Hilfe von [Struktur]-[Komponente]. Der Bindestrich wird deshalb auch Strukturkomponenten-Selektor genannt. Durch ihn erfolgt eine Verkettung von Strukturnamen bei geschachtelten Strukturen. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -7- Kapitel 5 Kapitel 6 REPORT YTU_MZ_DT. TYPES: BEGIN OF Lieferant, Nummer TYPE i, Name(30) TYPE c, Stadt(30), Strasse(40), END OF Lieferant. DATA: BEGIN OF Materialstammsatz, Nummer TYPE i, Name(30) TYPE c, BEGIN OF ort, Lagerort(20) TYPE c, Regalstandort(10), END OF ort, vorhandeneMenge TYPE i, Nachlieferdatum TYPE d, Nachlieferer TYPE Lieferant, END OF Materialstammsatz. *… Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -8- Kapitel 5 Kapitel 6 *… Materialstammsatz-Nummer = 123. Materialstammsatz-Name = 'Welle'. Materialstammsatz-ort-Lagerort = 'Lager-A'. Materialstammsatz-ort-Regalstandort = 'AX-234'. Materialstammsatz-vorhandeneMenge = 12. Materialstammsatz-Nachlieferdatum = '20020401'. Materialstammsatz-Nachlieferer-Nummer = 1. Materialstammsatz-Nachlieferer-Name = 'Mustermann GmbH'. Materialstammsatz-Nachlieferer-Stadt = 'Musterstadt'. Materialstammsatz-Nachlieferer-Strasse = 'Musterstrasse 1'. WRITE / Materialstammsatz. *Ausgabe als Zeichenkette *… Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 -9- Kapitel 5 Kapitel 6 *… WRITE: / Materialstammsatz-Nummer, Materialstammsatz-Name, Materialstammsatz-ort-Lagerort, Materialstammsatz-ort-Regalstandort, Materialstammsatz-vorhandeneMenge, Materialstammsatz-Nachlieferdatum DD/MM/YYYY, Materialstammsatz-Nachlieferer-Nummer, Materialstammsatz-Nachlieferer-Name, Materialstammsatz-Nachlieferer-Strasse, Materialstammsatz-Nachlieferer-Stadt. *korrekte Ausgabe Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 10 - Kapitel 5 Kapitel 6 Im obigen Beispiel wurde der Lagerort und der Regalstandort in eine Extrastruktur gepackt, da sie zusammengehören und nur gemeinsam eine eindeutige Klassifizierung des Ortes, an dem sich das Material befindet, zulassen. Der Lieferant wurde als Extrastruktur vereinbart und dem Material zugeordnet. So muss der Lieferant nicht jedes Mal neu eingegeben werden, sondern die Struktur kann für ein anderes Material wieder verwendet werden. Auch eine Redundanz der Daten wird somit vermieden. Des weiteren kann der gleiche Komponentenname mehrfach verwendet werden, ohne das dies zu Fehlern führt. Durch den Strukturnamen ist jede Komponente individuell ansprechbar. Dies ist in der Beispielstruktur bezüglich der Komponenten [Nummer] und [Name] der Fall. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 11 - Kapitel 5 Kapitel 6 Geschachtelte Strukturen: Bei geschachtelten Strukturen besteht eine Hierarchie von Strukturkomponenten. Dies spiegelt sich vor allem in der Verkettung der Namen wieder. Sollen die Komponenten einer Struktur in eine andere Struktur eingegliedert werden, diese aber alle auf der gleichen Ebene liegen, so muss die Anweisung INCLUDE verwendet werden. Die Anweisung INCLUDE unterbricht dabei den Kettensatz, der danach wieder neu begonnen werden muss. Syntax: DATA: BEGIN OF [Struktur1], [Felder], INCUDE STRUCTURE [Struktur2] AS [Strukturname] {RENAMING WITH SUFFIX [Suffix]}. [Felder], END OF [Struktur1]. Die Komponenten der Struktur [Struktur2] werden als Komponenten in die Struktur [Struktur1] übernommen, wodurch sie gemeinsam mit den anderen Komponenten adressierbar sind. Der Zusatz RENAMING ist notwendig, falls eine Komponente gleichen Namens existiert. Hierdurch wird die Eindeutigkeit der Komponente gewährleistet. So ist auch eine mehrmalige Einbindung der gleichen Komponente in die Struktur möglich. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 12 - Kapitel 5 Kapitel 6 REPORT YTU_MZ_DT. DATA: BEGIN OF Lieferant1, Nummer TYPE i, Name(30) TYPE c, Stadt(30), Strasse(40), END OF Lieferant1. DATA: BEGIN OF Lieferant2, Nummer TYPE i, Name(30) TYPE c, Stadt(30), Strasse(40), END OF Lieferant2. *… Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 13 - Kapitel 5 Kapitel 6 *… DATA: BEGIN OF Materialstammsatz, Nummer TYPE i, Name(30) TYPE c, Lagerort(20) TYPE c, Regalstandort(10), vorhandeneMenge TYPE i, Nachlieferdatum TYPE d. INCLUDE STRUCTURE Lieferant1 AS liefer1 RENAMING WITH SUFFIX_1liefer. INCLUDE STRUCTURE Lieferant2 AS liefer2 RENAMING WITH SUFFIX_2liefer. DATA END OF Materialstammsatz. *… Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 14 - Kapitel 5 Kapitel 6 *… Materialstammsatz-Nummer = 123. Materialstammsatz-Name = 'Welle'. Materialstammsatz-Lagerort = 'Lager-A'. Materialstammsatz-Regalstandort = 'AX-234'. Materialstammsatz-vorhandeneMenge = 12. Materialstammsatz-Nachlieferdatum = '20020401'. Materialstammsatz-Nummer_1liefer = 1. Materialstammsatz-Name_1liefer = 'Mustermann GmbH'. Materialstammsatz-Stadt_1liefer = 'Musterstadt'. Materialstammsatz-Strasse_1liefer = 'Musterstrasse 1'. Materialstammsatz-Nummer_2liefer = 2. Materialstammsatz-Name_2liefer = 'Test GbR'. Materialstammsatz-Stadt_2liefer = 'Testhausen'. Materialstammsatz-Strasse_2liefer = 'Testweg 1'. *… Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 15 - Kapitel 5 Kapitel 6 *… WRITE / Materialstammsatz. *Ausgabe als Zeichenkette WRITE: / Materialstammsatz-Nummer, Materialstammsatz-Name, Materialstammsatz-Lagerort, Materialstammsatz-Regalstandort, Materialstammsatz-vorhandeneMenge, Materialstammsatz-Nachlieferdatum DD/MM/YYYY, Materialstammsatz-liefer1-Nummer, Materialstammsatz-liefer1-Name, Materialstammsatz-liefer1-Strasse, Materialstammsatz-liefer1-Stadt, Materialstammsatz-liefer2-Nummer, Materialstammsatz-liefer2-Name, Materialstammsatz-liefer2-Strasse, Materialstammsatz-liefer2-Stadt. *korrekte Ausgabe Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 16 - Kapitel 5 Kapitel 6 Alle Komponenten liegen in diesem Beispiel auf einer Ebene. Namenskonflikte zwischen den Komponenten werden durch unterschiedliche Endungen vermieden. In den WRITE-Anweisungen werden die Namen verwendet, unter denen die Strukturen eingebunden wurden. So können unter anderem sehr lange Namensketten umgangen werden. Essentiell ist diese Form, wenn sie als Vorlage für Datenbanktabellen im ABAP-Dictionary verwendet werden sollen. Hier sind nämlich nur Strukturen zulässig, bei denen alle Komponenten auf der selben Ebene liegen. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 17 - Kapitel 5 Kapitel 6 Datentyp für Referenzen: Referenzen (Zeiger) dienen zur Zeit ausschließlich als Objektreferenzen oder als Datenreferenzen. Sie liegen in Referenzvariablen und dem Datentyp, der die Referenzvariablen bestimmt, vor. Wir unterscheiden zwischen Datenreferenzvariablen und Objektreferenzvariablen. Referenzvariablen werden in ABAP wie andere Datenobjekte mit elementarem Datentyp behandelt. Das bedeutet, dass eine Referenzvariable nicht nur als Einzelfeld, sondern auch als kleinste unteilbare Einheit komplexer Datenobjekte wie Strukturen oder interne Tabellen definiert werden kann. Die gehören zu den tiefen Typen, da sie keine Daten zur Verarbeitung, sondern nur Verweise auf andere Datenobjekte beinhalten. Möglichkeiten eine Referenzvariable mit einer Referenz zu versorgen: • Der Referenzvariable wird eine Referenz auf ein Datenobjekt beschafft. • Der Referenzvariable wird eine bestehende Datenreferenz aus einer anderen Referenzvariable zugewiesen. Mit einer Referenzvariable wird ein Datenobjekt dynamisch erzeugt. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 18 - Kapitel 5 Kapitel 6 Syntax: DATA / TYPES [Datenobjekt] TYPE REF TO [Datum]. *Datenreferenzen DATA / TYPES [Datenobjekt] TYPE REF TO [Klasse]. *Objektreferenzen Nach ihrer Deklaration ist eine Referenzvariable initial, d.h. sie enthält einen leeren Zeiger bzw. zeigt auf kein Objekt, wobei eine Dereferenzierung dieser Referenzvariablen nicht möglich ist. Hierbei erfolgt meist die Zuweisung von Referenzen zwischen Datenreferenzvariablen mit der MOVEAnweisung bzw. dem Zuweisungsoperator (=). Die beteiligten Operanden müssen als Datenreferenzvariable typisiert sein. Zuweisungen an Objektreferenzvariable oder andere Variable sind nicht möglich. Nach der Zuweisung zeigt die Referenz in der Zielvariable auf das gleiche Datenobjekt wie die Referenz in der Quellvariable. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 19 - Kapitel 5 Kapitel 6 Dereferenzierung: Um auf den Inhalt eines Datenobjektes zugreifen zu können, auf das eine Datenreferenz zeigt, muss diese zuerst dereferenziert werden. Dazu ist der Dereferenzierungsoperator (->*) nötig. Dabei wird dem Feldsymbol das Datenobjekt zugewiesen, auf das die Datenreferenz in der Referenzvariable zeigt. Syntax: ASSIGN [Datenreferenz] ->* TO [Feldsymbol]. REPORT YTU_MZ_Referenz. DATA: datenreferenz TYPE REF TO data, zahl TYPE i VALUE 5. FIELD-SYMBOLS [Feldsymbol] TYPE ANY. GET REFERENCE OF zahl INTO datenreferenz. ASSIGN datenreferenz->* TO [Feldsymbol]. WRITE / [Feldsymbol]. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 20 - Kapitel 5 Kapitel 6 In diesem Beispiel gibt es zwei Datenreferenzvariablen. Über sie erfolgt die Referenzierung der Datenobjekte zur Laufzeit. Am Ende des Programms zeigen sie auf das Datenobjekt Zahl. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 21 - Kapitel 5 Kapitel 6 Erzeugung dynamischer Datenobjekte: Alle bisherigen Datenobjekte wurden im Deklarationsteil statisch erzeugt. Um eines dynamisch (während der Laufzeit) zu erzeugen, benötigt man neben der Datenreferenzvariable auch noch die CREATE-Anweisung. Durch CREATE wird ein Datenobjekt im internen Modus erzeugt und die Datenreferenz zeigt nach Ausführung dieser Anweisung auf das Objekt. Die Dereferenzierung ist die einzige Möglichkeit, auf den Inhalt zuzugreifen. Ein dynamisches Objekt lebt so lange, wie eine Referenzvariable auf das Datenobjekt zeigt. Ist dies nicht mehr der Fall, so wird es automatisch gelöscht. Mit TYPE oder LIKE wird der Datentyp des Datenobjektes angegeben. Bei CREATE DATA kann der Datentyp dynamisch als Inhalt eines Feldes angegeben werden. Syntax: CREATE DATA Datenreferenz {TYPE / LIKE [Datenobjekt]}. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 22 - Kapitel 5 Kapitel 6 Verkettete Liste: Unter dem Einsatz von Datenreferenzvariablen können beliebig komplexe dynamische Datenstrukturen (Listen, Bäume) verwaltet werden. Sie sind ein sehr komplexes Konstrukt in ABAP, da die Liste: 1. vereinbart werden muss 2. in einer Schleife die Elemente angelegt werden 3. die Datenobjekte an die Liste angehängt werden müssen Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 23 - Kapitel 5 Kapitel 6 Beim Anschauen der Liste ist ebenfalls ein Programm nötig. *Vereinbarung REPORT YTU_MZ_Referenz. TYPES: BEGIN OF element, wert TYPE i, next TYPE REF TO data, END OF element. DATA: kopf TYPE REF TO data, neu TYPE REF TO data. FIELD-SYMBOLS [Feldsymbol] TYPE element. Um dieses komplexe Konstrukt zu umgehen, werden interne Tabellen benutzt. Im Rahmen dieses Kurses wird auch nur auf diese eingegangen, da komplexe Datenstrukturen wahrscheinlich einen extra Kurs füllen würden. Wer nähere Informationen zu diesen Strukturen haben möchte, sollte sich in der SAP-Onlinehilfe informieren. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 24 - Kapitel 5 Kapitel 6 Aufgaben: 1. Schreiben Sie ein Programm, in dem sie einen Personalstammsatz (Nummer, Name, Straße, Ort, Postleitzahl, Geburtsdatum) vereinbaren. Lesen Sie passende Daten dazu ein und geben Sie diese auch korrekt wieder aus. 2. Ändern Sie das obige Beispiel so ab, dass eine Unterstruktur im Programm vorliegt. Fügen Sie eine zusätzliche Struktur Schüler (mit Nummer und Name) ein. 3. Gehen Sie von den Aufgaben 1 und 2 aus und bringen Sie die geschachtelte Struktur Schüler auf die gleiche Ebene wie Personalstammsatz. Integrieren Sie die Struktur Schüler als eine Komponente, bestehend aus Komponenten gleichen Namens, noch einmal. Geben Sie ABAP und Objekts als zwei Zeichenketten aus, in dem Sie diese zuvor mit Referenzvariablen vereinbaren und dereferenzieren. Hinweis: Es ist keine Listenstruktur gefordert. Kapitel 1 Komplexe Strukturen Kapitel 2 Kapitel 3 Kapitel 4 - 25 - Kapitel 5 Kapitel 6 Modularisierung Herzstück des prozeduralen Programmiermodells ist die Modularisierung. Hier werden die Programme in funktionale Einheiten mit lokalen Datenbereichen eingeteilt. Prozeduren sind Verarbeitungsblöcke mit lokalem Datenbereich und Parameterschnittstelle. Sie können innerhalb deselben Programms oder aus anderen Programmen heraus aufgerufen werden. Durch sie können Programme gezielt modularisiert und wieder verwendbare Softwarebausteine bereitgestellt werden. Prinzipiell sind ABAP-Programme schon durch ihre Verarbeitungsblöcke modularisiert, da jedes ABAP-Programm einen Ereignisblock benötigt, um ausführbar zu sein. Allerdings werden so Aspekte der Datenkapselung nicht berücksichtigt, da diese Aufrufe keine Parameterschnittstelle und keinen lokalen Datenbereich besitzen. Ziel des Abschnittes ist es, grundlegende Modularisierungstechniken, die auch aus anderen Programmiersprachen bekannt sind, anhand von ABAP darzulegen. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -1- Kapitel 4 Kapitel 5 Kapitel 6 Organisation von externen Prozeduraufrufen: Jede Ausführung eines startbaren Programms öffnet einen eigenen internen Modus. Beim Aufruf von externen Prozeduren werden deren Rahmenprogramme und Arbeitsdaten in den Speicherbereich des internen Modus geladen. Dabei wird in der prozedualen Programmierung zwischen dem Aufruf von externen Unterprogrammen und dem Aufruf von Funktionsbausteinen unterschieden. Ein Aufruf eines Funktionsbausteins einer bisher nicht geladenen Funktionsgruppe öffnet eine Zusatzprogrammgruppe, in der die Funktionsgruppe des Funktionsbausteins abgelegt wird. Die Zusatzprogrammgruppe bleibt mit ihren Daten für die gesamte Lebensdauer des internen Modus vorhanden. Ein Aufruf eines externen Unterprogramms lädt das Rahmenprogramm, in dem das Unterprogramm steht, zum Hauptprogramm bzw. zur Funktionsgruppe in die Haupt- bzw. Zusatzprogrammgruppe, falls es bisher noch nicht geladen wurde. Es werden ausschließlich die Bildschirme (Dynpros, Selektionsbilder, Listen) angezeigt und verarbeitet. Die Anweisungen CALL SCREEN, CALL SELECTION-SCREEN oder ListenausgabeAnweisungen wirken auf die Bildschirme des Hauptprogramms bzw. der Funktionsgruppe. Die Bildschirmbearbeitung findet ebenfalls im Hauptprogramm bzw. der Funktionsgruppe statt. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -2- Kapitel 4 Kapitel 5 Kapitel 6 Vorteile von Prozeduren: 1. Lesbarkeit des Programms: Bei großen Programmen ist die Modularisierung für Außenstehende und Entwickler essentiell, um das Augenmerk auf das Wesentliche zu richten, das Gesamtverständnis zu fördern und die Übersichtlichkeit zu wahren. 2. Wartbarkeit des Programms: Die Softwarekomponente kann mehrmals verwendet werden, weswegen eine Modularisierung den Umfang des Quelltextes reduziert und eine Änderung innerhalb des Moduls nur einmal geschehen muss, während sonst an allen Stellen geändert wird. 3. Datenkapselung: Die Daten der Funktion sind lokal und nur während der Ausführung der Prozedur vorhanden. Im wesentlichen wird zwischen interner Modularisierung mittels Unterprogrammen oder externer mittels Funktionsbausteinen unterschieden. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -3- Kapitel 4 Kapitel 5 Kapitel 6 Es erfolgt die Aufteilung des Quelltextes des ABAP-Programms entsprechend seiner Funktionalität. Unterprogramme können aus dem selben Programm oder einem anderen Programm heraus aufgerufen werden. Da externe Modularisierung vorzugsweise über Funktionsbausteine geregelt wird, wird im Weiteren auf lokale Unterprogrammaufrufe eingegangen werden. In ABAP werden Unterprogramme vorzugsweise am Ende eines Quelltextes angelegt. Unterprogramme lassen sich aus Unterprogrammen aufrufen (geschachtelte Aufrufe) und Unterprogramme können auch sich selbst aufrufen (rekursive Aufrufe). Nach erfolgreicher Beendigung des aufgerufenen Unterprogramms wird die Ausführung des aufrufenden Programms nach der PERFORM-Anweisung fortgesetzt. Ihr Inhalt steht zwischen FORM und ENDFORM. Durch USING und CHANGING werden Parameterschnittstellen definiert. Syntax: *Unterprogrammvereinbarung FORM [Unterprogrammname]. (Programmbausteine) ENDFORM. *Unterprogrammaufruf: PERFORM [Unterprogrammname] {USING [Parameter]}. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -4- Kapitel 4 Kapitel 5 Kapitel 6 REPORT YTU MZ unterprogramme. START-OF-SELECTION. PERFORM unterprogramm1. FORM unterprogramm1. PERFORM unterprogramm2. ENDFORM. FORM unterprogramm2. WRITE 'ABAP'. ENDFORM. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -5- Kapitel 4 Kapitel 5 Kapitel 6 Eine wichtige Möglichkeit beim Umgang mit Unterprogrammen ist die Übergabe von Parametern, da sie dadurch allgemein gehalten werden können. Arten der Parameterdefinition sind: 1. USING [parameter]: Für den Parameter wird kein lokales Datenobjekt im Unterprogramm angelegt. Beim Aufruf wird eine Referenz auf den Aktualparameter (gelten nur im aktuellen Unterprogramm) übergeben. Wird der Formalparameter (übergeordneter Parameter, der auch für das aktuelle Unterprogramm gültig ist) des Unterprogramms geändert, so wirkt sich dies direkt auf den Aktualparameter aus. 2. USING VALUE: Der Formalparameter legt ein lokales Datenobjekt als Kopie des Aktualparameters im Unterprogramm an. Der Wert des Aktualparameters wird an den Formalparameter übergeben. Wird der Formalparameter des Unterprogramms geändert, so wirkt sich dies nicht auf den Aktualparameter aus (Eingabeparameter). Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -6- Kapitel 4 Kapitel 5 Kapitel 6 3. CHANGING [parameter]: CHANGING hat die selbe Funktion wie USING, sollte aber aus Gründen der Übersichtlichkeit für Formalparameter, die sich im Unterprogramm ändern, verwendet werden. USING sollte dagegen für Formalparameter, die sich im Unterprogramm nicht ändern, verwendet werden. 4. CHANGING VALUE [parameter]: CHANGING VALUE arbeitet ähnlich wie USING VALUE, kopiert jedoch die lokale Kopie des Aktualparameters, wenn das Programm korrekt abgelaufen ist, in den Aktualparameter zurück. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -7- Kapitel 4 Kapitel 5 Kapitel 6 Eine Typisierung der Formalparameter ist notwendig, da die übergebenen Aktualparameter ganz unterschiedliche Datentypen haben können. Dies wird durch die Zusätze TYPE und LIKE realisiert. Hinter TYPE können hierbei alle möglichen Datentypen und hinter LIKE alle Datenobjekte angegeben werden. Bei der Übergabe des Aktualparameters erfolgt eine Datentypprüfung, wodurch nur typverträgliche Datentypen zugelassen werden. Der entscheidende Vorteil der Typisierung von Formalparamatern ist, dass die technischen Eigenschaften der Formalparameter schon bei der Programmierung bekannt sind. Es muss allerdings auch immer für jeden Formalparameter ein Aktualparameter angegeben werden, dessen Datentyp mit der Typisierung des Formalparameters verträglich ist. Der erste Aktualparameter in PERFORM wird dem ersten Formalparameter zugewiesen. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -8- Kapitel 4 Kapitel 5 Kapitel 6 REPORT YTU_MZ_unterprogramme. DATA: nummer TYPE p DECIMALS 2, zahl TYPE i, zahl1 TYPE i, zahl2 TYPE i, sum TYPE i. zahl1 = 2. zahl2 = 6. PERFORM test USING nummer zahl. PERFORM summe USING zahl1 zahl2 CHANGING sum. *… Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 -9- Kapitel 4 Kapitel 5 Kapitel 6 *… FORM test USING value(num) TYPE p int TYPE i. DATA: t(1) TYPE c. DESCRIBE FIELD num DECIMALS t. WRITE: / 'Decimals of NUM are', t. DESCRIBE FIELD int TYPE t. WRITE: / 'Type of INT is', t. ENDFORM. *… Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 10 - Kapitel 4 Kapitel 5 Kapitel 6 *… FORM summe USING summe_zahl1 TYPE any summe_zahl2 TYPE any CHANGING summe_sum TYPE any. summe_sum = summe_zahl1 + summe_zahl2. PERFORM ausgabe USING summe_zahl1 summe_zahl2 summe_sum. ENDFORM. FORM ausgabe USING ausgabe_zahl1 TYPE any ausgabe_zahl2 TYPE any ausgabe_sum TYPE any. WRITE: / 'Summe: ', ausgabe_zahl1, 'and', ausgabe_zahl2, 'is', ausgabe_sum. ENDFORM. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 11 - Kapitel 4 Kapitel 5 Kapitel 6 Funktionsbausteine: Funktionsbausteine gehören zu den Prozeduren. Sie dienen der Kapselung und Wiederverwendbarkeit von globalen Bausteinen und werden in einer zentralen Funktionsbibliothek verwaltet. Es existieren zahlreiche vordefinierte Funktionsbausteine in ABAP, die aus jedem ABAPProgramm aufgerufen werden können. Sie sind nur innerhalb eines ABAP-Programms (Funktionsgruppen vom Typ f) definiert, aber aus allen ABAP-Programmen aufrufbar. Für das Anlegen von Funktionsgruppen und Funktionsbausteinen ist das Werkzeug Function Builder der ABAP-Workbench nötig. Der Unterschied zu ABAP-Unterprogrammen liegt in der Definition der Schnittstelle. Diese erfolgt nicht im Programmtext, sondern mit dem Function Builder. Außerdem können gezielt Fehler während der Ausführung abgefangen und Funktionsbausteine auch eigenständig getestet werden. Das Werkzeug Function Builder beinhaltet ein Freigabeverfahren für Funktionsbausteine, das sicherstellt, dass freigegebene Funktionsbausteine nicht mehr inkompatibel geändert werden, wodurch ein Programm, das freigegebene Funktionsbausteine verwendet immer lauffähig bleibt. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 12 - Kapitel 4 Kapitel 5 Kapitel 6 Syntax: *Funktionsvereinbarung FUNCTION [Funktionsname]. (Programmbausteine) ENDFUNCTION. *Funktionsaufruf: CALL FUNCTION [Funktionsname]. Funktionsgruppen: Funktionsgruppen sind nicht ausführbare Rahmenprogramme für Funktionsbausteine. Wenn ein Funktionsbaustein aufgerufen wird, so erfolgt das Laden der gesamten Funktionsgruppe in den internen Modus des aufrufenden Programms. Funktionsgruppen kapseln Daten vor dem Aufrufen von Funktionsbausteinen und stellen somit eine Vorstufe zu den Klassen von ABAP dar. Alle Funktionsbausteine einer Funktionsgruppe haben gemeinsamen Zugriff auf die globalen Daten der Gruppe, weswegen solche Funktionsbausteine in einer Funktionsgruppe zusammengefasst werden sollten. Funktionsgruppen können verschiedenartige Komponenten enthalten. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 13 - Kapitel 4 Kapitel 5 Kapitel 6 Funktionsbausteine aufrufen: Funktionsbausteine werden aus der Funktionsbibliothek aufgerufen, wobei man nach bestimmten Schritten vorgeht: 1. Nach vorhandenen Funktionsbausteinen im Function Builder suchen, die die gewünschte Funktionalität aufweisen. Wichtige Attribute: a) Dokumentation (beschreibt die Aufgabe des Funktionsbausteins, Schnittstellenparameter) b) Schnittstellenparameter und Ausnahmen (Informationen darüber, wie der Funktionsbaustein zu behandeln ist) 2. Funktionsbausteine sollten vor dem Einbau in ein Programm getestet werden. Im ABAP-Workbench sind nähere Informationen zum Testen von Funktionsbausteinen im Function Builder und dem Funktionsbausteinaufruf in ABAP enthalten. Der Aufruf der Funktionsbausteine erfolgt über CALL FUNCTION. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 14 - Kapitel 4 Kapitel 5 Kapitel 6 Syntax: CALL FUNCTION [Funktionsname] [EXPORTING SP1 = AP1.... SP n = APn] *alle nicht-optionalen Import-Parameter *müssen typgerecht versorgt werden [IMPORTING SP1 = AP1.... SPn = APn] *Es können die Export-Parameter von typgerechten *Aktualparametern übernommen werden. [CHANGING SP1 = AP1.... SPn = APn] [TABLES SP SP1 = AP1.... SPn = APn] *alle nicht-optionalen Changing- bzw. Tabellen *Parameter müssen typgerecht versorgt werden und *werden nach Beendigung wieder von den Aktualparametern übernommen. [EXCEPTIONS A1 = R1.... SP n = An {ERROR_MESSAGE = [Nachricht]} [OTHERS = ro]]. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 15 - Kapitel 4 Kapitel 5 Kapitel 6 Mit der Option EXCEPTIONS können die Ausnahmen [A] behandelt werden, die während der Funktionsbausteinausführung ausgelöst werden können, wobei die Auslösung zur Unterbrechung der Abarbeitung führt und keine Werte außer Referenzen ausgegeben werden. Das aufrufende Programm behandelt die Ausnahme, indem es SY-SUBRC den Wert [A] zuweist, und diesen als Zahlenliteral angibt. ERROR_MESSAGE dient hier zur Nachrichtenbehandlung. Die Nachrichten der Klassen S, I, und W werden ignoriert und die Klassen E und A beenden den Funktionsbaustein. Die Erklärung zu den Nachrichtenklassen kann in der SAP-Hilfe eingesehen werden. Mit Hilfe von OTHERS werden sämtliche Ausnahmen, die nicht explizit aufgeführt werden, einem einzigen Rückgabewert zugewiesen. Durch die Zuordnungen [Schnittstellenparameter] = [Aktualparameter] wird jedem der verwendeten Schnittstellenparameter [SP] ein aktueller Parameter [AP] zugeordnet und jeder Ausnahme [A] kann eine Rückgabewert [R] zugeordnet werden. Die einfachste Vorgehensweise für den statischen Aufruf eines Funktionsbausteins ist das Einfügen eines Anweisungsmusters im ABAP-Editor durch CALL FUNCTION und Angabe des Namens des gewünschten Funktionsbausteins. Modularisierung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 Kapitel 5 Kapitel 6 - 16 - *Zeichenkettensplit in zwei Teilzeichenketten. REPORT YTU_MZ_funktionen. DATA: text(5) TYPE c VALUE '56789', teil1(3) TYPE c, teil2(3) TYPE c. PARAMETERS p TYPE i. *Aufruf des Funktionsbausteins CALL FUNCTION 'Zeichenkettensplit' EXPORTING string = text pos = p IMPORTING string1 = teil1 string2 = teil2 EXCEPTIONS string1_too_small = 1 string2_too_small = 2 pos_not_valid = 3 OTHERS = 4. *… Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 17 - Kapitel 4 Kapitel 5 Kapitel 6 *… CASE sy-subrc. WHEN 0. WRITE: / text, / text1, / text2. WHEN 1. WRITE 'Target field 1 too short!'. WHEN 2. WRITE 'Target field 2 too short!'. WHEN 3. WRITE 'Invalid split position!'. WHEN 4. WRITE 'Other errors!'. ENDCASE. Dieses Beispiel ist nur aus Gründen des Verständnises angefügt. Auf Grund dessen, dass Funktionen nicht einfach im ABAP-Editor erzeugt werden können, sind sie im praktischen Bereichen nicht Inhalt des Kurses. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 18 - Kapitel 4 Kapitel 5 Kapitel 6 Funktionsbausteine anlegen: Funktionsbausteine werden ausschließlich mit dem Function Builder der ABAP-Workbench angelegt. Es sind Bezüge auf systemweit bekannte Datentypen, welche die elementaren ABAP-Datentypen, systemweit bekannten generischen Typen und die im ABAP-Dictionary definierten Typen sind, möglich. Für die Übergabe der Daten an das aufrufende Programm benötigt der Funktionsbaustein einen Export-Parameter. Als nächstes kann der Programmtext in den Funktionsbaustein eingefügt werden. Dies erfolgt zwischen FUNCTION und ENDFUNCTION nach den selben Regeln wie bei anderen Programmen. Man hat aber auch noch Zugriff auf alle globalen Daten des Rahmenprogramms. Sowohl Unterprogramme als auch Funktionsbausteine können verwendet werden. Ausnahmen werden durch zwei funktionsbausteinspezifische Anweisungen (RAISE [Ausname]. und MESSAGE... RAISING [Ausname].) ausgeführt. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 19 - Kapitel 4 Kapitel 5 Kapitel 6 *Funktion FUNCTION test. IF SY-DATUM = '20020328'. WRITE 'TEST'. ENDIF. ENDFUNCTION. *Programm REPORT YTU_MZ _funktionen. CALL FUNCTION 'test'. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 20 - Kapitel 4 Kapitel 5 Kapitel 6 Ablauf der Entwicklung: 1. Überprüfen Sie ob ein ähnlicher Funktionsbaustein existiert. Wenn dies nicht zutrifft. 2. Legen Sie eine Funktionsgruppe an, falls noch keine geeignete Gruppe existiert. 3. Legen Sie den Funktionsbaustein an. 4. Definieren Sie die Schnittstelle, indem Sie dessen Parameter und Ausnahmen festlegen. 5. Programmierung des Funktionsbausteins. 6. Aktivieren Sie den Baustein. 7. Testen Sie den Baustein. 8. Dokumentieren Sie den Baustein und seine Parameter für andere Benutzer. 9. Geben Sie den Baustein zur allgemeinen Benutzung frei. Mit Hilfe des Modifikationsassistenten können Funktionsbausteine hinzugefügt und existierende Funktionsbausteine modifiziert werden. Im ABAP-Editor können im Programm Modifikationen vorgenommen werden. Das Programm ist dazu intern in sogenannte Modularisierungseinheiten gegliedert, zu denen Module, Unterprogramme und Ereignisse gehören. Weiterführende Informationen zum Thema Funktionen finden Sie in der SAP-Onlinehilfe. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 21 - Kapitel 4 Kapitel 5 Kapitel 6 Weitere Module: Include: Include-Programme dienen ausschließlich der Modularisierung von Quelltext und haben keine Parameterschnittstelle und können nicht unabhängig laufen, sondern müssen in andere Programme eingebunden werden. Sie erfüllen eine Bibliotheksfunktion zur Wiederverwendung von Quelltext in verschiedenen Programmen. Um selbst ein Include-Programm anlegen zu können, müssen Sie das Programmattribut I für den Typ verwenden. Einschränkungen für Include-Programme ergeben sich dahingehend, dass sie sich nicht selbst einbinden können und vollständige Anweisungen enthalten müssen. Include-Programme werden nicht dynamisch zur Laufzeit geladen, sondern bei der Programmgenerierung ausgelöst. Nach der Generierung enthält das Laufzeitobjekt statisch alle eingebundenen Include-Programme. Die INCLUDE-Anweisung muss die einzige Anweisung in der Zeile sein und kann nicht über mehrere Zeilen geschrieben werden. Syntax: *Includeaufruf INCLUDE [incl]. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 22 - Kapitel 4 Kapitel 5 Kapitel 6 ***INCLUDE starttxt WRITE sy-datum. REPORT YTU_MZ_include. WRITE 'Heute ist der: '. INCLUDE test. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 23 - Kapitel 4 Kapitel 5 Kapitel 6 Makros: Bei längeren Berechnungen oder komplexen WRITE-Ausgaben kann es sinnvoll sein, die gleiche Anweisungsfolge mehrmals wiederzuverwenden. Die Codierung dazu kann einmalig in einem Makro erfolgen, wobei diese nur lokal im Programmtext und dort nur für nachfolgende Zeilen zur Verfügung. Syntax: *Makroaufruf [makro] {[p1] [p2]... [p9]}. *Makro DEFINE [makro]. [anweisungen] END-OF-DEFINITION. Zwischen DEFINE und END-OF-DEFINITION müssen vollständige Anweisungen angeben werden, wobei bis zu neun Platzhalter "und"1, "und"2,...., "und"9 zulässig sind. Eine Makro-Definition führt an beliebiger Position des Programmtexts sozusagen eine Abkürzung ein, die dann in allen nachfolgenden Zeilen dieses Programmtexts verwendet werden kann. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 24 - Kapitel 4 Kapitel 5 Kapitel 6 REPORT YTU_MZ_makro. DATA: ergebnis TYPE i, n1 TYPE i VALUE 5, n2 TYPE i VALUE 6. DEFINE operation. ergebnis = "und"1 "und"2 "und"3. END-OF-DEFINITION. operation 4 + 3. WRITE: / 'Ergebnis : ', "und"4. *Oder dieses Programm DEFINE macro. WRITE '...'. ENDFORM. END-OF-DEFINITION. FORM test. MACRO. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 25 - Kapitel 4 Kapitel 5 Kapitel 6 Fehlerbehandlung: ABAP ist eine sehr vielfältige Sprache und hat eine sehr strenge Syntax. Zum Beispiel kann schon ein falsch oder gar nicht gesetztes Leerzeichen zu Fehlern führen. Dadurch wird es gerade am Anfang häufig zu Fehlern bei der Erstellung von Programmen kommen. Während sich semantische Fehler häufig erst nach einer Anzahl von Testfällen ergeben, sind syntaktische Fehler viel leichter zu finden. Auch manche Syntaxfehler können erst zur Laufzeit identifiziert werden, aber ein Großteil ist schon während der Programmerstellung erkennbar. Dies sind die sogenannten statischen Fehler. Programme mit Fehlern dieser Klasse sind in der Regel nicht ausführbar. Ist das Programm syntaktisch korrekt, so kann es zwar ausgeführt werden, aber auch auf Anweisungen stoßen, die nicht ausgeführt werden können. Das System weist dann einen Laufzeitfehler aus. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 26 - Kapitel 4 Kapitel 5 Kapitel 6 Statisch erkennbare Fehler: Zum Auffinden statisch erkennbarer Fehler stellt ABAP eine automatische Syntaxprüfung und die erweiterte Programmprüfung bereit. 1. Syntaxprüfung: Die Syntaxprüfung kann jederzeit durch Prüfen aufgerufen werden. Wenn man die Prüfung nicht manuell startet, so wird sie automatisch vor dem ersten Programmstart durchgeführt. Wenn Fehler auftauchen, wird sie unterbrochen und die Fehlermeldung inklusive Lösungsvorschlag wird ausgegeben. Statisch erkennbares Beispiel: Des Weiteren werden in ABAP Warnungen angezeigt. Die Behebung dieser ist nicht zwingend notwendig, sollte aber nach Möglichkeit durchgeführt werden, da sonst durchaus Fehler während der Laufzeit entstehen können. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 27 - Kapitel 4 Kapitel 5 Kapitel 6 2. Erweiterte Programmprüfung: Die gesamte Palette möglicher Prüfungen wird nicht bei jeder Syntaxprüfung durchgeführt. Zumindest einmal vor der Fertigstellung sollte eine erweiterte Prüfung durchgeführt werden, um alle erkennbaren statischen Fehler zu eliminieren. Der Aufruf erfolgt über Programm Æ Prüfen Æ Erweiterte Programmprüfung. Auch bei der erweiterten Programmprüfung werden zusätzlich Warnungen ausgegeben, die die gleiche Bedeutung wie bei der 'normalen' Syntaxprüfung haben. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 28 - Kapitel 4 Kapitel 5 Kapitel 6 Laufzeitfehler: Wenn während der Programmausführung Fehler auftauchen, so wird ein Laufzeitfehler ausgelöst. Dabei wird zwischen abfangbaren und nicht-abfangbaren unterschieden. Abfangbare Laufzeitfehler: Laufzeitfehler sind abfangbar, wenn sie auf Situationen zurückzuführen sind, die sinnvoll im Programm behandelt werden können. Sie können in Fehlerklassen zusammengefasst werden, wodurch ähnliche Fehler gemeinsam behandelt werden können. Syntax: CATCH SYSTEM-EXCEPTIONS Fehlerklasse1 = Zahlenliteral1 ... Fehlerklasse2 = Zahlenliteral2. ... ENDCATCH. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 29 - Kapitel 4 Kapitel 5 Kapitel 6 Sollte einer der angegebenen Laufzeitfehler zwischen CATCH und ENDCATCH auftreten, so wird zu ENDCATCH gesprungen und nicht wie sonst das Programm abgebrochen. Allerdings können nur Laufzeitfehler der aktuellen Ebene abgefragt werden. Fehler in Prozeduren, die im geprüften Abschnitt aufgerufen werden sind nicht lokalisierbar. Mit dem Systemfeld SY-SUBRC kann das, der Fehlerklasse zugeordnete, Zahlenliteral ausgegeben werden. Eine Auflistung sämtlicher abfragbarer Laufzeitfehler, deren Zuordnung zu Fehlerklassen und deren Zuordnung zu Schlüsselwörtern findet sich in der Schlüsselwortdokumentation zu CATCH. REPORT YTU_MZ_Fehlerbehandlung. DATA: ergebnis TYPE p DECIMALS 2, nummer TYPE i VALUE 0. CATCH SYSTEM-EXCEPTIONS arithmetic_errors = 4. ergebnis = 1 / nummer. ENDCATCH. IF SY-SUBRC = 4. WRITE / 'Arithmetischer Fehler'. *arithmetischer Fehler und wird über diese abgefangen ENDIF. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 30 - Kapitel 4 Kapitel 5 Kapitel 6 Auch dieses Beispiel soll den Sachverhalt nur veranschaulichen. Die Anwendung ist nicht Gegenstand dieses Kurses. Nicht abfangbare Laufzeitfehler: Nicht abfangbare Laufzeitfehler liegen vor, wenn sie auf Zustände zurückzuführen sind, die eine Fortführung des ABAP-Programms keinesfalls zulassen. Das Programm erzeugt einen Kurzdump und zeigt diesen an. Der Kurzdump dient zur Ausgabe der Fehlerinformationen. Zu diesen zählen zum Beispiel aktive Aufrufe. Kurzdumps werden dabei normalerweise 14 Tage gespeichert. Um diese Spanne auf unbegrenzte Zeit zu verlängern, benötigt man die Funktion Aufbewahren. Sollte eine eigenständige Problembehebung unmöglich sein, so können relevante Auszüge an SAP gesendet werden. Es gibt dabei die Möglichkeit der Remote-Beratung und der Hotline. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 31 - Kapitel 4 Kapitel 5 Kapitel 6 Kurzdump Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 32 - Kapitel 4 Kapitel 5 Kapitel 6 Aufgaben: 1. Schreiben Sie ein einfaches Programm zur Referenzübergabe von Parametern an Unterprogramme (UP). Das UP soll eine Addition zweier Zahlen vornehmen. 2. Verändern Sie das obige Programm so, dass Sie Unterprogramme verschachteln (z. B. Ausgabe in einem weiteren UP). 3. Lösen sie die obige Aufgabe unter Zuhilfename eines Makros. Kapitel 1 Kapitel 2 Modularisierung Kapitel 3 - 33 - Kapitel 4 Kapitel 5 Kapitel 6 Datenbehandlung Nachdem wir nun die Quelltextmodularisierung kennen gelernt haben werden wir uns noch mit der Datenbehandlung des prodeduralen Programmiermodells beschäftigen. Des Weiteren dient dieses Kapitel als Übergang zur Objektorientierung, da alles hier gesagte seine Gültigkeit in der objektorientierten Welt behält und nur noch durch das Klassen-Konzept ergänzt wird. Deklarationen von Variablen können in ABAP in zwei Kontexten erfolgen. Erstens die Deklaration innerhalb von Prozeduren und zweitens die Deklaration außerhalb von Prozeduren. Hierbei nennen wir die innerhalb von Prozeduren deklarierten Variablen lokal und die außerhalb deklarierten global. In der objektorientierten Welt von ABAP käme jetzt noch als dritter Kontext die Klasse hinzu. In den nun folgenden Kapiteln Sichtbarkeit und Lebensdauer beschäftigen wir uns nun mit der Auswirkung des Kontextes auf die Sichtbarkeit und Lebensdauer von Variablen. Kapitel 1 Kapitel 2 Datenbehandlung Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Sichtbarkeit: Die Sichtbarkeit in dem prozeduralen Programmiermodell von ABAP ist von innen nach außen hin definiert. D.h., alle Anweisungen einer Prozedur können auf die lokalen Datenobjekte der Prozedur wie auch auf alle globalen Datenobjekte zugreifen. Hat ein lokales Datenobjekt den gleichen Namen wie ein globales, so wird das globale durch das lokale überdeckt. Die Datenobjekte einer Prozedur sind von außen allerdings nicht sichtbar, d.h. aus dem ABAP-Rahmenmodell heraus können keine Datenobjekte von Prozeduren angesprochen werden. Weiterhin können ABAP-Programme nicht auf die globalen Datenobjekte anderer ABAP-Programme zugreifen, während alle Prozeduren eines ABAP-Programms auf die globalen Datenobjekte zugreifen können. Hier wäre noch zu erwähnen, dass für die Attribute von Klassen die Sichtbarkeit selbst definiert werden kann, so dass hier auch eine Sichtbarkeit von außen zugelassen werden kann. Mehr dazu siehe Kapitel „Klassen“. Kapitel 1 Kapitel 2 Datenbehandlung Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Lebensdauer: Prinzipiell ist zu sagen, dass Datenobjekte nur so lange leben wie ihre Kontexte. D.h., dass lokale Daten einer Prozedur nur so lange im Speicher vorhanden sind wie die Ausführung der Prozedur dauert. Bei einer erneuten Ausführung der Prozedur würde wieder ein neurer Kontext mit den entsprechenden Datenobjekten entstehen. Die globalen Datenobjekte einen ABAP-Programms hingegen sind während der gesamten Laufzeit des Programms vorhanden. Wie man sehen kann wird die Lebensdauer von Datenobjekten implizit durch die Lebensdauer der zugehörigen Kontexte definiert. Man hat keine Möglichkeiten Datenobjekte „von Hand“ aus dem Speicher zu entfernen. Da der Kontext die Lebensdauer des Datenobjekts steuert, werden Sie feststellen, dass in ABAP-Objects die Objekte für die Lebensdauer der Datenobjekte zuständig sind. Mit anderen Worten: in ABAP-Objects ist die Klasse der Kontext eines Datenobjektes. Solange das Objekt der Klasse existiert, existieren auch die Datenobjekte. Kapitel 1 Kapitel 2 Datenbehandlung Kapitel 3 Kapitel 4 -3- Kapitel 5 Kapitel 6 Exkurs Objektorientierung Im letzten Kapitel haben wir die Modularisierung und die Sichtbarkeit von Datenobjekten im klassischen Programmiermodell näher betrachtet. Dieses Kapitel beschäftigt sich nun mit den Grundlagen von ABAP Objects. Als erstes wollen wir klären was Objektorientierung bedeutet: In unserer realen Welt identifizieren wir Dinge als Objekte und weisen ihnen gewisse Eigenschaften und Funktionen zu. Nehmen wir als Beispiel hier einen Monitor. Ein Monitor hat die Eigenschaften AN, AUS und dir Funktionen ein/ausschalten. In der objektorientierten Welt nennen wir nun die Eigenschaften Attribute und die Funktionen Methoden. Ein weiteres Beispiel wäre eine Windows-Standardanwendung (ein Button auf einer Form). Der Button besitzt die Attribute Höhe, Breite, Gedrückt etc. und die Methode Drücken. Ein Beispiel aus der betriebswirtschaftlichen Welt wäre das Objekt Kunde oder Rechnung. Bei der objektorientierten Programmierung ist es nun das Ziel diese Objekte der Realwelt so naturgetreu wie möglich abzubilden und die Programmabläufe so zu gestallten, wie sie in der realen Welt stattfinden würden. Kapitel 1 Kapitel 2 Exkurs Objektorientierung Kapitel 3 Kapitel 4 -1- Kapitel 5 Kapitel 6 Im klassischen Programmierparadigma haben wir gesehen, dass Attribute und Methoden strikt getrennt wurden. D.h. die Modellierung der realen Welt fand dort auf der Basis der Daten statt. Im objektorientierten Modell wird dagegen ein ganz anderer Ansatz verfolgt. Hier werden Attribute und Methoden, die zu einem Objekt gehören, zusammengefasst (gekapselt) und dem Anwender dieses Objektes über definierte Schnittstellen zugänglich gemacht. Dabei sollte immer sichergestellt werden, dass die Attribute einen Objekts nur durch dessen Methoden geändert werden und nicht direkt von dem Anwender. Eine Programmiersprache nennen wir nun objektorientiert, wenn sie folgende vier Merkmale aufweist: 1. Abstraktion 2. Kapelsung 3. Vererbung 4. Polymorphie Definieren wir zunächst diese Begriffe. Kapitel 1 Kapitel 2 Exkurs Objektorientierung Kapitel 3 Kapitel 4 -2- Kapitel 5 Kapitel 6 Abstraktion: Abstraktion bedeutet die Fähigkeit, Abläufe der Realwelt möglichst naturgetreu in einer Programmiersprache wiederzugeben. Diese Abläufe können nun betriebswirtschaftlicher oder technischer Natur sein. Realweltprobleme werden während der Programmierung in Klassen modelliert und während der Programmausführung durch Instanzzierung in Objekten abgebildet. Kapselung: Die Details der Implementierung werden hinter wohldefinierten und dokumentierten Schnittstellen verborgen. D.h. wird während der Programmierung ein Realweltobjekt modelliert, so werden alle Attribute und Methoden dieses Objekts zusammen in einer Klasse abgebildet. Der Zugriff auf die Attribute sollte nun lediglich über die Methoden erfolgen, um das gesamte Objekt in einem konsistenten Zustand zu halten. Vererbung: Vererbung bedeutet, dass neue Abstraktionen (Klassen) aus bereits bestehenden abgeleitet werden können und somit alle Attribute wie auch Methoden übernehmen. Diese neu abgeleiteten Abstraktionen können nun spezialisiert und erweitert werden. Von einer Klasse Fahrzeug könnte man z.B. die Unterklassen PKW und LKW ableiten und spezialisieren. Die Klassen PKW und LKW können nun wieder durch Vererbung spezialisiert werden. Exkurs Objektorientierung Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 Kapitel 5 Kapitel 6 -3- Polymorphie: Polymorphie meint, unterschiedliche Objekte nach außen hin durch gleiche Schnittstellen zu präsentieren. Dies hat den Vorteil, dass der Verwender lediglich die Schnittstellen kennen muss, um auf Objekte verschiedener Klassen zugreifen zu können. Sind einem Benutzer die grundlegenden Bedienelemente eines Autos bekannt, also die Schnittstellen, so kann er fast alle Autos fahren, ohne zu wissen welche Klasse Auto er eigentlich nutzt. Bei eine Programmiersprache, die diese vier Eigenschaften unterstützt, spricht man von einer objektorientierten Programmiersprache. Allerdings ist nicht jedes Programm, welches man in dieser Sprache schreibt, auch wirklich objektorientiert. Im Falle von ABAP hat es wenig Sinn Reports, die vom Rest des Systems völlig losgelöst sind, objektorientiert zu schreiben. Zu diesem Exkurs wäre nun abschließend zu sagen, dass der objektorientierte Programmierstil zu einem sauberen und sicheren Code führt, der die Programme letztlich einfacher und pflegbarer macht als im klassischen ABAP. Kapitel 1 Kapitel 2 Exkurs Objektorientierung Kapitel 3 Kapitel 4 -4- Kapitel 5 Kapitel 6 Klassen Die Grundlage jeder objektorientierten Programmiersprache sind Klassen. Diese dienen als Vorlage (Schablone, Template) eines Objekts wie ein Datentyp Vorlage eines Datenobjekts ist. Man nennt daher auch eine Klasse Objekttyp. Auf der Grundlage von einer Klasse kann man nun verschiedene Objekte erzeugen, wobei die Attribute jedes Objekts unterschiedliche Ausprägungen haben können. Eine derartige Ausprägung einer Klasse nennen wir Instanz, die Erzeugung eines Objekts Instanziierung. Nun unterscheiden wir lokale und globale Klassen. Lokale Klassen werden innerhalb eines beliebigen ABAP-Programms definiert und sind nur dort sichtbar. Im Gegensatz dazu werden globale Klassen mit dem Class Builder des ABAP Workbench in der Klassenbibliothek angelegt und sind somit in jedem ABAP-Programm sichtbar. Die Verwendung von globalen und lokalen Klassen ist abgesehen von ihrer Sichtbarkeit völlig identisch. Im weiterem Kursverlauf wollen wir uns nur mit lokalen Klassen beschäftigen. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -1- Kapitel 5 Kapitel 6 Klassendefinition: Die Definition von Klassen erfolgt in ABAP immer über die Anweisungen CLASS und ENDCLASS. Eine Klassendefinition besteht immer aus einem Deklarationsteil und einem Implementierungsteil. Im Deklarationsteil erfolgt hierbei die Beschreibung der einzelnen Komponenten der Klasse, wobei die einzelnen Komponenten Attribute, Methoden oder Ereignisse sein können. Im Implementierungsteil werden nun die einzelnen Methoden implementiert. Syntax: CLASS class DEFINITION. … ENDCLASS CLASS class IMPLEMENTATION. … ENDCLASS. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -2- Kapitel 5 Kapitel 6 Sichtbarkeitsbereiche: Im Deklarationsteil der Klasse muss jeder Komponente ein Sichtbarkeitsbereich zugeordnet werden, um die Schnittstellen der Klasse nach außen hin überschaubar zu halten (Kapselung). Würde man nun beispielsweise eine Komponente nach außen hin sichtbar machen, könnte sie von außen geändert und somit das gesamte Objekt in einen inkonsistenten Zustand versetzt werden. Attribute einer Klasse sollten nie von außen veränderbar sein sondern nur durch öffentliche Methoden geändert werden. ABAP kennt hier 3 Sichtbarkeitsbereiche: - PUBLIC: Alle diesem Bereich zugeordnete Komponenten sind öffentlich und von allen Verwendern ansprechbar. Die bilden die Schnittstelle nach außen. - PROTECTED: Alle Komponenten dieses Bereichs sind lediglich durch Methoden der Unterklassen (Erben) und durch Methoden der Klasse selbst ansprechbar. - PRIVATE: Alle Komponenten dieses Bereichs sind privat und können nur von den Methoden der Klasse selbst verwendet werden. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -3- Kapitel 5 Kapitel 6 Syntax: CLASS class DEFINITION. PUBLIC SECTION. … PROTECTED SECTION. … PRIVATE SECTION. … ENDCLASS. Komponente einer Klasse: Nun gehen wir etwas tiefer auf die einzelnen Komponenten einer Klasse ein. Neben der Sichtbarkeit der Komponenten kann man für die einzelnen Komponenten auch die Lebensdauer festlegen. Dabei unterscheiden wir zwischen Instanzkomponenten und statischen Komponenten. Instanzkomponenten sind in jedem Objekt einer Klasse unabhängig voneinander vorhanden. Statische Komponente sind dagegen nur einmal pro Klasse vorhanden, d.h. alle Objekte einer Klasse teilen sich diese Komponente. Hier wäre noch zu erwähnen, dass statische Komponenten einer Klasse verwendet werden können, ohne das eine Instanz der Klasse erzeugt wurde. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -4- Kapitel 5 Kapitel 6 Attribute: Attribute sind die Datenobjekte einer Klasse. Diese spiegeln den Zustand eines Objekts wieder. Attribute können - wie Variablen aus dem 2. Kapitel - allen Datentypen angehören. Zur Deklaration von Instanzattributen verwendet man die Anweisung DATA. Zur Deklaration von statischen Attributen CLASS-DATA. REPORT YTU_MGRO_CLASS_ATTRIBUTES . * Klassen Deklaration CLASS attributes DEFINITION. PRIVATE SECTION. DATA obj_value TYPE i. CLASS-DATA obj_count TYPE i. ENDCLASS. Es ist natürlich ebenso möglich selbstdefinierte Typen innerhalb einer Klasse zu deklarieren. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -5- Kapitel 5 Kapitel 6 Methoden: In Methoden ist das Verhalten der Objekte einer Klasse implementiert. Dabei sind Methoden daselbe wie Prozeduren, die wir schon kennen gelernt haben. Allerdings können Methoden lediglich innerhalb einer Klasse genutzte werden. Methoden sind dabei Verarbeitungsblöcke mit einer Parameterschnittstelle. In ihnen können nun wieder lokale Daten deklariert werden Wie auch bei den Attributen kann man Methoden in Instanzmethoden und statische Methoden einteilen. Instanzmethoden können auf Attribute und Ereignisse ihrer eigenen Klasse zugreifen, statische Methoden nur auf statische Attribute und statische Ereignisse. Instanzmethoden kann man dabei nur nutzen, wenn ein Objekt der Klasse erzeugt worden ist. Methoden werden dabei an zwei Stellen einer Klassendefinition aufgeführt. Einmal werden Methoden im Deklarationsteil bekannt gemacht. Dabei werden Instanzmethoden mit der Anweisung METHODS deklariert und statische Methoden mit CLASS-METHODS. Hier werden auch die Parameter der Methode definiert. Des Weiteren wird der eigentlich auszuführende Code einer Methode zwischen den Anweisungen METHODS und ENDMETHODS im Implementierungsteil der Klasse implementiert. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -6- Kapitel 5 Kapitel 6 REPORT YTU_MGRO_CLASS_ATTRIBUTES . * Klassen Deklaration CLASS attributes_and_methods DEFINITION. PUBLIC SECTION. METHODS: set_obj_value IMPORTING VALUE(i_obj_value) TYPE i, get_obj_value EXPORTING VALUE(e_obj_value) TYPE i. PRIVATE SECTION. DATA obj_value TYPE i . CLASS-DATA obj_count TYPE i. ENDCLASS. *… Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -7- Kapitel 5 Kapitel 6 *… * Klassen Implementierung CLASS attributes_and_methods IMPLEMENTATION. METHOD set_obj_value. obj_value = i_obj_value. ENDMETHOD. METHOD get_obj_value. e_obj_value = obj_value. ENDMETHOD. ENDCLASS. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -8- Kapitel 5 Kapitel 6 In diesem Beispiel ist zu sehen wie Methoden in einer Klasse deklariert und anschließend implementiert werden. Zu beachten ist, dass bei der Deklaration von mehreren Methoden nach METHODS ein Doppelpunkt geschrieben werden muss und die einzelnen Methoden durch Kommata getrennt werden. Des Weiteren wird durch IMPORTING VALUE ein Parameter erwartet und durch EXPORTING VALUE ein Rückgabewert definiert. Die Funktionsweise des Beispiels ist einfach. Durch get_obj_value (öffentliche Methode) wird der Wert eines privaten Attributs verändert und durch set_obj_value wird dieser Wert ausgelesen und zurückgegeben. Des Weiteren ist zu sagen, dass es noch zwei spezielle Methoden innerhalb einer Klasse gibt. Dies wären die Methode namens constructor, die implizit bei jeder Instanzierung eines neuen Objektes aufgerufen wird und die Methode class_constructor, die beim ersten Zugriff auf eine Klasse aufgerufen wird. Eine genauere Erklärung zu diesen beiden Methoden erfolgt später. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 -9- Kapitel 5 Kapitel 6 Ereignisse: Im Definitionsteil einer Klasse können Ereignisse als Komponenten einer Klasse deklariert werden. Nach einer solchen Deklaration können alle Methoden der gleichen Klasse die Ereignisse auslösen. Andere Methoden derselben oder einer anderen Klasse können mit speziellen Behandlerklassen auf diese Ereignisse reagieren. Aufgrund der Komplexität der Ereignisbehandlung gehen wir in diesem Kurs nicht darauf ein. Kapitel 1 Kapitel 2 Klassen Kapitel 4 Kapitel 3 - 10 - Kapitel 5 Kapitel 6 Objekte Bis jetzt haben wir uns nur mit dem Aufbau und der Implementierung einer Klasse beschäftigt. Bis zu diesem Zeitpunkt macht das ABAP-Programm noch nichts. In diesem Abschnitt wollen wir nun Objekte, also Instanzen einer Klasse erzeugen. Objekte erzeugen und referenzieren: Bei einer Objektreferenzen handelt es sich um nichts anderes als um die Adresse des Objekts im Speicher. Eine Referenzvariable ist nun ein Datenobjekt, das Objektsreferenzen enthält und somit auf ein Objekt zeigt. Dabei ist zu bemerken, dass auch mehrere Referenzvariablen auf ein Objekt zeigen können. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -1- Kapitel 5 Kapitel 6 REPORT YTU_MGRO_FIRST_OBJECT . * Klassen Deklaration CLASS vehicle DEFINITION. PUBLIC SECTION. METHODS: accelerate, show_speed. PRIVATE SECTION. DATA speed TYPE i VALUE 0. ENDCLASS. * Klassen Definition CLASS vehicle IMPLEMENTATION. METHOD accelerate. speed = speed + 1. ENDMETHOD. *… Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -2- Kapitel 5 Kapitel 6 *… METHOD show_speed. WRITE: / speed. ENDMETHOD. ENDCLASS. *Globale Daten DATA obj1 TYPE REF TO vehicle. * Ausfuerungsblock START-OF-SELECTION. CREATE OBJECT obj1. CALL METHOD obj1->accelerate. CALL METHOD obj1->accelerate. CALL METHOD obj1->accelerate. CALL METHOD obj1->show_speed. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -3- Kapitel 5 Kapitel 6 Als erstes haben wir eine Klasse vehicle definiert, wobei diese Klasse über ein privates Attribut speed und zwei öffentliche Methoden verfügt. Speed dient dabei der Messung der aktuellen Geschwindigkeit, die Methode accelerate beschleunigt, also erhöht speed um eins und die Methode show_speed gibt einfach die aktuelle Geschwindigkeit aus. Das eigentlich neue an diesem Beispiel ist hier DATA obj1 TYPE REF TO vehicle. Hier wird nun ein Zeiger auf die Objektreferenz erzeugt. Der Zusatz REF TO bewirkt, dass eine Referenzvariable eine Objektreferenz enthalten kann. Nachdem nun ein Zeiger auf die Objektreferenz zeigt kann man eine neues Objekt instanzieren. Dies geschieht mit der Anweisung CREATE OBJECT obj1. Zum jetzigen Zustand haben wir also ein Objekt der Klasse vehicle und eine Referenz auf dieses Objekt. Nun können wir anfangen mit diesem Objekt zu arbeiten. Hier kann man nun mittels der Objektreferenz auf die Schnittstellen der Klasse, also den öffentlichen Komponenten zugreifen. In unserem Beispiel sprechen wir also die öffentlichen Methoden mit CALL METHOD an. Zuweisungen zwischen Referenzvariablen können ebenso wie bei Variablen vorgenommen werden. So könnte man unser Beispiel wie folgt abändern: Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -4- Kapitel 5 Kapitel 6 *… *Globale Daten DATA: obj1 TYPE REF TO vehicle, obj2 LIKE obj1. * Ausfuerungsblock START-OF-SELECTION. CREATE OBJECT obj1. obj2 = obj1. CALL METHOD obj2->accelerate. CALL METHOD obj2->accelerate. CALL METHOD obj2->accelerate. CALL METHOD obj2->show_speed. Hier haben wir eine zweite Referenzvariable vom Typ vehicle erzeugt. Zu beachten ist, dass wir kein neues Objekt erzeugt haben. Diese Referenz lassen wir mittels obj2 = obj1 auf das Objekt obj1 zeigen. Nun können wir auf die Schnittellen des Objektes mit obj1 und mit obj2 zugreifen. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -5- Kapitel 5 Kapitel 6 Verwendung von Objektkomponenten: Die Verwendung von Objektkomponenten erfolgt grundsätzlich nach dem Schema: 1. Referenzvariable deklarieren 2. Objekt erzeugen 3. Objektkomponenten nutzen. Der Zugriff auf Objektkomponenten, egal ob Attribut oder Methode, erfolgt durch den Operator ->. Syntax: obj_ref -> comp Bei dem Zugriff auf statische Komponenten einer Klasse muss kein Objekt erzeugt werden. Der Zugriff erfolgt mittels dem => Operator. Es wird hierbei auch keine Referenzvariable genutzt sondern der Klassenname an sich. Syntax: class => comp Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -6- Kapitel 5 Kapitel 6 Selbstreferenzierung: Wie wir gesehen haben, erfolgt der Zugriff auf Methoden von außen durch die Referenzvariable und den Methodenname. Wird eine Methode innerhalb des Objekts aufgerufen genügt lediglich der Methodenname. Allerdings ist es möglich, dass ein Objekt seine eigene Adresse, also seine Referenz kennen muss, um z. B. seine eigene Identität an ein weiteres Objekt zu übergeben. Hierzu kann man die vordefinierte Referenzvariable me verwenden, die während der Ausführung einer Methode immer eine Referenz auf die Adresse des eigenen Objekts enthält. Des weiteren ist me nützlich, zur Adressierung von Attributen der eigenen Klasse in Methoden, die über gleichnamige lokale Datenobjekte verfügen und dadurch die Attribute verdecken. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -7- Kapitel 5 Kapitel 6 REPORT YTU_MGRO_SELF_REFERENCE . * Klassen Definition CLASS client DEFINITION. PUBLIC SECTION. DATA name(10) TYPE c VALUE 'Master' READ-ONLY. METHODS create_server. ENDCLASS. CLASS server DEFINITION. PUBLIC SECTION. METHODS acknowledge IMPORTING creator TYPE REF TO client. PRIVATE SECTION. DATA name(10) TYPE c VALUE 'Servant'. ENDCLASS. *… Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -8- Kapitel 5 Kapitel 6 *… * Klassen Implementation CLASS client IMPLEMENTATION. METHOD create_server. DATA server_ref TYPE REF TO server. CREATE OBJECT server_ref. CALL METHOD server_ref->acknowledge EXPORTING creator = me. ENDMETHOD. ENDCLASS. CLASS server IMPLEMENTATION. METHOD acknowledge. DATA name TYPE string. name = creator->name. WRITE: me->name, 'created by', name. ENDMETHOD. ENDCLASS. *… Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 -9- Kapitel 5 Kapitel 6 *… DATA client_ref TYPE REF TO client. START-OF-SELECTION. CREATE OBJECT client_ref. CALL METHOD client_ref->create_server. Dieses jetzt schon etwas konplexere Beispiel erzeugt ein Objekt der Klasse client und ruft deren Methode create_server auf. Diese Methode erzeugt nun wieder ein Objekt der Klasse server. Graphisch dargestellt sähe dies so aus (vereinfacht): Objekt der Klasse client Kapitel 1 Kapitel 2 Objekt der Klasse server Objekte Kapitel 4 Kapitel 3 - 10 - Kapitel 5 Kapitel 6 Die Methode create_server ruft nun acknowledge im erzeugten Objekt auf und übergibt dabei ihre Selbstreferenz an den Parameter creator. Diese Methode acknowledge greift nun über die übergebene Referenz auf das öffentliche Attribut name der Klasse client zu und übergibt dessen Inhalt ihrer lokalen Variablen name. In der Anweisung WRITE greift die Methode dann über ihre Selbstreferenz auf das private Attribut name der eigenen Klasse zu, das durch die lokale Variable verdeckt wird. Die Ausgabe ist dann: „Servant created by Master“. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 11 - Kapitel 5 Kapitel 6 Mehrfache Instanzierung: Bis jetzt haben wir gesehen, wie wir eine Klasse mit ihren Attributen und Methoden deklarieren, implementieren und dann ein Objekt der Klasse bilden. Aber alles was wir bis jetzt in den Beispielen behandelt haben, hätten wir auch über die Funktionsbausteine lösen können. D.h. wir hätten auch Funktionen schreiben können, die unsere speed-Variable erhöhen oder sie ausgeben. Aber was würden wir machen, wenn wir fünf Fahrzeuge hätten, die ihre speed-Variable jeweils zu anderen Zeitpunkten erhöhen oder ausgeben wollen? Wir müssten, um dies zu realisieren, entweder unsere Funktionen mehrfach in den Code einfügen oder eine aufwendige Fahrzeugbehandlung in den Funktionen implementieren. Um dieser doch etwas unübersichtlichen und fehleranfälligen Programmierung entgegenzuwirken nutzen wir an dieser Stelle Objekte. Wir deklarieren und implementieren eine Klasse und erzeugen dazu fünf Objekte der Klasse. Da jedes Objekt über die entsprechenden Schnittstellen verfügt und ihre eigenen Variablen hat, ist es ausreichend die einzelnen Fahrzeug-Objekte namentlich zu kennen. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 12 - Kapitel 5 Kapitel 6 REPORT YTU_MGRO_SEVERAL_OBJECTS . * Klassen Deklaration CLASS vehicle DEFINITION. PUBLIC SECTION. METHODS: accelerate, show_speed. PRIVATE SECTION. DATA speed TYPE i VALUE 0. ENDCLASS. * Klassen Definition CLASS vehicle IMPLEMENTATION. METHOD accelerate. speed = speed + 1. ENDMETHOD. *… Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 13 - Kapitel 5 Kapitel 6 *… METHOD show_speed. WRITE: / speed. ENDMETHOD. ENDCLASS. *Globale Daten DATA: obj TYPE REF TO vehicle, obj_tab TYPE TABLE OF REF TO vehicle. * Ausfuerungsblock START-OF-SELECTION. DO 5 TIMES. CREATE OBJECT obj. APPEND obj TO obj_tab. ENDDO. LOOP AT obj_tab INTO obj. DO sy-tabix TIMES. CALL METHOD obj->accelerate. ENDDO. CALL METHOD obj->show_speed. ENDLOOP. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 14 - Kapitel 5 Kapitel 6 In diesem Beispiel erzeugen wir erst einmal fünf verschiedene Fahrzeug-Objekte mittels einer DO x TIMES Anweisung und legen die Objektreferenzen direkt nach der Erzeugung des Objekts in einer internen Tabelle ab, d.h. in jeder Zeile der internen Tabelle befindet sich nun eine Objektreferenz. Die einzelne Referenzvariable obj weist wie die letzte Zeile der Tabelle auf das zuletzt erzeugte Objekt. Die erzeugten Objekte leben nun völlig unabhängig voneinander im selben Speicherbereich und haben jeweils eine eindeutige Identität. Bis hierhin können wir nun also beliebig viele Objekte erzeugen und diese mittels einer internen Tabelle verwalten. Nach der Erzeugung der einzelnen Objekte lesen wir nun die interne Tabelle zeilenweise in obj ein, beschleunigen die Fahrzeuge auf unterschiedliche Geschwindigkeiten und geben die Geschwindigkeit des jeweiligen Objekts aus. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 15 - Kapitel 5 Kapitel 6 Objekte löschen: Da im Laufe der Programmausführung Objekte erzeugt werden liegt es nahe, dass die erzeugten Objekte auch wieder gelöscht werden müssen. Um ein Objekte quasi „anzufassen“, benötigen wir eine Referenzvariable, die uns den Zugriff auf das Objekt ermöglicht. Zeigt nun während der Programmausführung keine Referenz mehr auf ein bestimmtes Objekt, so wird der Garbage Collector aktiv und löscht das Objekt. Dieser Garbage Collector wird von der Laufzeitumgebung aufgerufen, so dass sich der Programmierer nicht darum kümmern muss. Der Garbage Collector wird während der Laufzeit periodisch aufgerufen und sucht nach Objekten, auf die keine Referenz mehr zeigt. Besitzt so ein Objekt nun Attribute vom Typ einer Referenz, so verfolgt der Garbage Collector die Referenz und prüft ob diese auf ein weiteres Objekt zeigen. Wenn es derartige Objekte gibt und wenn auf diese Objekte keine anderen Referenzen verweisen, so werden das ursprüngliche Objekt, wie auch das gefundene Objekte gelöscht. Objekte, die nicht mehr benötigt werden, können auch manuell vom Programmierer selbst gelöscht werden. Dazu verwenden Sie die Anweisung CLEAR. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 16 - Kapitel 5 Kapitel 6 REPORT YTU_mgro_garbage_collector. … DATA: obj1 TYP REF TO vehicle, obj2 LIKE obj1. START-OF-SELECTION. CEATE OBJECT: obj1, obj2. obj1 = obj2. CLEAR obj2. In diesem Beispiel deklarieren wir zunächst zwei Referenzvariablen vom Typ vehicle. Danach erzeugen wir zwei verschiedene Objekte, auf die diese Referenzen verweisen. Da wir dann der Referenz obj1 die Referenz obj2 zuweisen zeigt nun keine Referenz mehr auf das eigentliche Objekt von obj1. Nach einiger Zeit wird dieses Objekt nun also vom Garbage Collector gelöscht. Mit der Anweisung CLEAR obj2 erreichen wir nun, dass nur noch obj1 auf das zweite Objekt verweist und nur noch dieses es am Leben hält. Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 17 - Kapitel 5 Kapitel 6 Aufgabe: Erstellen Sie in einem Programm eine Klasse „Text“ mit der Methode „Ausgabe“. Und geben Sie einen beliebigen Text aus. Danach legen Sie 5 Objekte dieser Klasse an, lassen den Text der Methode „Ausgabe“ ausgeben und löschen die Objekte wieder! Kapitel 1 Kapitel 2 Objekte Kapitel 4 Kapitel 3 - 18 - Kapitel 5 Kapitel 6 Methoden In den letzen Beispielen haben wir nun schon einige Methoden definiert und diese im Laufe des Programms aufgerufen. Nun wollen wir die Parameterschnittstellen von Methoden etwas genauer untersuchen. Parameterschnittstelle: Um einer Methode Parameter übergeben zu können, ist es nötig, die Anweisung METHODS im Deklarationsteil zu ändern. Im Implementierungsteil sind dagegen keine Änderungen nötig. Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -1- Kapitel 5 Kapitel 6 Syntax: METHODS meth IMPORTING … {VALUE(i) | i} {TYPE type | LIKE dobj} [OPTIONAL | DEFAULT def] EXPORTING … {VALUE(e) | e} {TYPE type | LIKE dobj} CHANGING … {VALUE(c) | c} {TYPE type | LIKE dobj} [OPTIONAL | DEFAULT def] EXEPTIONS … x … Zur Erklärung: - IMPORTING: Festlegen von einem oder mehreren Eingabeparametern. - EXPORTING: Festlegen von einem oder mehreren Ausgabeparametern. - CHANGING: Festlegen von einem oder mehreren Parametern, die sowohl Eingabe- als auch Ausgabeparameter sind. Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -2- Kapitel 5 Kapitel 6 Nun kann man mittels Zusätzen die Eigenschaften der einzelnen Formalparametern festlegen: 1. Übergabeart: Hier kann man nun festlegen, ob der Parameter als Referenz oder als Wert übergeben wird. Standardmäßig wird der Parameter als Referenz übergeben. Dies kann man nun mittels dem Zusatz VALUE ändern. Es ist ebenso möglich die Referenzübergabe explizit festzulegen, indem man anstelle von VALUE REFERENCE angibt. 2. Typisierung: Hier muss nun der Typ des zu übergebenen Parameters genannt werden oder dieser mittels LIKE nach außen hin sichtbar gemacht werden. 3. Optionale Parameter / Startwert: Hier kann nun dem zu übergebenen Parameter mittels DEFAULT ein Startwert zugewiesen werden. Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -3- Kapitel 5 Kapitel 6 Der Aufruf einer Methode könnte nun wie folgt aussehen: CALL METHOD meth ( ). CALL METHOD meth ( a ). CALL METHOD meth ( f1 = a1 … fn = an ). Funktionale Methoden: Bis hierhin haben Sie gesehen, wie man Methoden definiert und ihnen Parameter übergibt. Allerdings sind Sie es von anderen Programmiersprachen gewohnt, Methoden anstatt mittels speziellen Aufrufanweisungen (CALL), durch Ausdrücke in Operationen aufzurufen. Vorrausetzung dafür sind allerdings funktionale Methoden, die wie folgt aussehen: METHODS meth IMPORTING … {VALUE(i) | i} {TYPE type | LIKE dobj} [OPTIONAL | DEFAULT def] RETURNING VALUE(r) {TYPE type | LIKE dobj}. Dabei hat eine funktionale Methode beliebig viele IMPORTING-Parameter, aber genau einen RETURNING-Parameter. Dieser Rückgabeparameter muss nun als Wert übergeben und vollständig typisiert werden. Methoden Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 Kapitel 5 Kapitel 6 -4- CALL METHOD oref->meth EXPORTING i = a … j = b RECIEVING r = c. Der Zusatz RECIEVING ordnet nun dem RETURNING-Parameter einen Aktualparameter zu. Im folgenden Beispiel, in dem eine Kreisfläche berechnet wird, wird nun dargestellt wie Methoden mittels CALL METHOD und funktional aufgerufen werden. REPORT YTU_MGRO_FUNCTIONAL_METHOD. * Class Declaration CLASS circle DEFINITION. PUBLIC SECTION. METHODS get_area IMPORTING VALUE(i_radius) TYPE i RETURNING VALUE(r_size) TYPE f. PRIVATE SECTION. CONSTANTS pi TYPE f VALUE '3.14159265'. ENDCLASS. *… Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -5- Kapitel 5 Kapitel 6 *… *Class Implementations CLASS circle IMPLEMENTATION. METHOD get_area. r_size = i_radius ** 2 * pi. ENDMETHOD. ENDCLASS. *Global Data PARAMETERS radius TYPE i. DATA: o_circle TYPE REF TO circle, Area TYPE f. *Classical Processing Blocks START-OF-SELECTION. CREATE OBJECT o_circle. CALL METHOD o_circle->get_area EXPORTING i_radius = radius RECEIVING r_size = area. WRITE: / 'Klassisch: ', area. *… Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -6- Kapitel 5 Kapitel 6 *… *Functional Processing Blocks area = o_circle->get_area( radius ). WRITE: / 'Funktional: ', area. Der Eingabebildschirm, der am Programmanfang zu sehen ist, wird durch den Befehl PARAMETERS erzeugt. Diese ist ein Vorgriff auf das Kapitel „Bildschirmbilder“ und dient hier nur der Veranschaulichung. Er wird in dem folgenden Kapitel näher erläutert. Kapitel 1 Kapitel 2 Methoden Kapitel 4 Kapitel 3 -7- Kapitel 5 Kapitel 6 Konstruktoren In den bisherigen Beispielen wurden die Methoden einer Klasse immer durch den Programmierer selbst erstellt und der Aufrufzeitpunkt festgelegt. In diesem Kapitel werden nun die besonderen Methoden einer Klasse vorgestellt, die so genannten Konstruktoren. Ein Konstruktor ist eine spezielle Methode, die automatisch von der Laufzeitumgebung ausgeführt wird. Sie wird eingesetzt, um ein Objekt dynamisch in einen definierten Anfangszustand zu versetzen. Ein Konstruktor kann nicht mittels CALL METHOD aufgerufen werden und der Programmierer kann auch keinen Einfluss auf dessen Aufrufzeitpunkt nehmen. Wie auch bei den schon bekannten Methoden werden Konstruktoren in instanzabhängige und in instanzunabhängige Ausprägungen unterteilt. Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -1- Kapitel 5 Kapitel 6 Instanzkonstruktor: Instanzkonstruktoren werden für jede Instanz einer Klasse genau einmal nach der vollständigen Erzeugung mittels CREATE OBJECT aufgerufen. Diese Instanzkonstruktoren müssen ebenso wie „normale“ Methoden im Deklarationsteil einer Klasse deklariert werden und im Implementationsteil der Klasse implementiert werden. Hierbei sind nun zwei Regeln zu beachten: 1. die Methode muss den vordefinierten Namen constructor haben 2. die Methode muss in der PRIVAT SECTION deklariert werden. Syntax: METHODS constructor IMPORTING … {VALUE(i) | i} {TYPE type | LIKE dobj} [OPTIONAL | DEFAULT def] EXCEPTION … x … Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -2- Kapitel 5 Kapitel 6 Wie zu sehen ist, hat ein Konstruktor keinen Ausgabeparameter. Dies veranschaulicht, dass Konstruktoren nur dazu dienen den Objektzustand zu definieren und kein Verhalten zur Verfügung zu stellen. Da ein Konstruktor implizit während der Anweisung CREATE OBJECT aufgerufen wird, müssen die Formalparameter während dieser Anweisung versorgt werden. Tritt eine Exception bei der Abarbeitung des Konstruktors auf, so wird das durch CREATE OBJECT erzeugte Objekt gleich wieder gelöscht und die entsprechende Referenzvariable wieder auf ihren Initialwert gesetzt. REPORT YTU_MGRO_CONSTRUCTOR. * Klassen Deklaration CLASS vehicle DEFINITION. PUBLIC SECTION. METHODS: constructor, accelerate, show_speed. PRIVATE SECTION. DATA speed TYPE i . ENDCLASS. *… Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -3- Kapitel 5 Kapitel 6 *… * Klassen Definition CLASS vehicle IMPLEMENTATION. METHOD constructor. speed = 100. ENDMETHOD. METHOD accelerate. speed = speed + 1. ENDMETHOD. METHOD show_speed. WRITE: / speed. ENDMETHOD. ENDCLASS. *Globale Daten DATA: obj1 TYPE REF TO vehicle. *… Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -4- Kapitel 5 Kapitel 6 *… * Ausfuerungsblock START-OF-SELECTION. CREATE OBJECT obj1. CALL CALL CALL CALL CALL METHOD METHOD METHOD METHOD METHOD obj1->show_speed. obj1->accelerate. obj1->accelerate. obj1->accelerate. obj1->show_speed. In diesem Beispiel sehen wir, wie ein Instanzkonstruktor verwendet wird. Im Deklarationsteil der Klasse wurde der constructor deklariert und im Implemenatationsteil mit dem init-Wert 100 belegt. Im Ausführungsblock wird als erstes der Initialwert der Variable speed ausgegeben mit dem durch den Konstruktor erzeugten Wert von „100“. Danach wird der durch die Beschleunigung erhöhte Wert abermals ausgegeben. Man kann hier sehen, das mittels eines Konstruktors der Initialzustand eines jeden Objekts definiert werden kann, der dann nach jeder Erzeugung eines Objekts feststeht. Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -5- Kapitel 5 Kapitel 6 Statische Konstruktoren: Der statische Konstruktor wird in einem Programm für jede Klasse genau einmal vor dem ersten Zugriff auf die Klasse aufgerufen. Wie beim Instanzkonstruktor muss der statische Konstruktor ebenfalls in der PUBLIC SELECTION deklariert werden. Der Name des statischen Konstruktors, mit dem er deklariert und implementiert wird, lautet class_constructor. In diesem Kurs wollen wir nicht weiter auf die statischen Konstruktoren eingehen und uns vorrangig mit den Instanzkonstuktoren beschäftigen. Dekonstruktor: Wenn ein Objekte über eine Konstruktormethode verfügt, die immer aufgerufen wird, wenn das Objekt gerade erzeugt wurde, könnte man annehmen, dass es ebenso eine Methode zum Löschen des Objekts gibt. Eine derartige Methode, ein Dekonstruktor, wurde auch in vielen Programmiersprachen dem Entwickler zur Verfügung gestellt. Allerdings stellt ABAP Objects keine derartige Methode aus Performancegründen bereit. Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -6- Kapitel 5 Kapitel 6 Aufgaben: 1. Es soll ein Programm zur Addition zweier Zahlen erstellt werden. Legen Sie dazu eine Klasse mit den Attributen a, b und summe und einer Methode zur Addition an. Lassen Sie danach das Programm mit verschiedenen Werten für a und b ablaufen. 2. Erweitern Sie das letzte Programm so, dass aus der Methode zur Addition eine funktionale Methode wird! Ändern Sie den Funktionsaufruf entsprechend! 3. Ergänzen Sie das letzte Programm um einen Konstruktor, der die Werte a und b auf 13 setzt und summe nullt! Kapitel 1 Kapitel 2 Kapitel 3 Konstruktoren Kapitel 4 -7- Kapitel 5 Kapitel 6 Arbeiten mit internen Tabellen In dieser Lerneinheit soll verdeutlicht werden, wie interne Tabellen aufgebaut sind, welche Arten es gibt und welche Vorteile sie gegenüber anderen Datentypen in ABAP besitzen. Weitere Lernziele sind: bevorzugtes Einsatzgebiet interner Tabellen, besondere Eigenschaften, sowie interne Verwaltung. Wie mit solchen Tabellen gearbeitet wird und welche Kommandos benötigt werden, wird in dieser Lerneinheit gezeigt. Hier soll in erster Linie die Theorie dieses Themengebietes vermittelt werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -1- Kapitel 6 Allgemeine Eigenschaften interner Tabellen: Das Besondere an internen Tabellen ist, dass sie nur im Hauptspeicher existieren. Sie sind also nicht zur dauerhaften Speicherung von Daten geeignet. Der Zweck ist vielmehr der, dass während der Laufzeit einer Anwendung Daten temporär gespeichert und bearbeitet werden. Da es in ABAP keine Arrays gibt, sind interne Tabellen die einzige Möglichkeit, gleichartige Datensätze zusammenzufassen. Ein weiterer Vorteil gegenüber Arrays ist, dass interne Tabellen dynamisch sind. Bei Arrays ist es im Allgemeinen so, dass man die Menge der Datensätze vorher kennen muss (siehe Psacal oder C). Die Größe von internen Tabellen (also die Anzahl der Zeilen) kann sich während der Laufzeit ändern. Mit Hilfe von internen Tabellen können Daten, die mittels der SELECT-Anweisung aus externen Tabellen einer Datenbank extrahiert wurden, zur weiteren Bearbeitung gepuffert werden. Weitere Anwendungsgebiete sind u. a. der Datenaustausch zwischen Unterprogrammen oder Funktionsbausteinen, sowie Sortierung oder Verdichtung von Datenbeständen nach bestimmten Kriterien. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -2- Kapitel 6 Aufbau interner Tabellen: Interne Tabellen bestehen aus mehreren Zeilen eines bestimmten Zeilentypes, der wie eine Struktur vereinbart wird. Der Zeilentyp kann ein beliebiger einfacher oder strukturierter Datentyp sein, also auch eine Tabelle (Schachtelung). Da eine interne Tabelle dynamisch im Hauptspeicher existiert, braucht sich der Anwender keine Sorgen um die Größe, also die Anzahl der Zeilen, zu machen. Eine interne Tabelle kann mit oder ohne Kopfzeile vereinbart werden. Jede Tabelle hat einen Schlüssel zur Identifikation der Tabellenzeile. Dieser kann entweder von Benutzer festgelegt werden (benutzerdefinierter Schlüssel), oder es wird ein Standardschlüssel erzeugt. Der benutzerdefinierte Schlüssel kann aus beliebigen Spalten der internen Tabelle aufgebaut werden, die selber keine interne Tabellen sind oder enthalten. Ist die Tabelle eine mit einem einfachen, nicht strukturierten Zeilentyp, so ist der gesamte Inhalt der Zeile Standardschlüssel. Ist der Zeilentyp strukturiert, so bilden alle nicht numerischen Spalten den Standardschlüssel. Schlüssel können als eindeutig UNIQUE oder nicht eindeutig NONUNIQUE definiert werden. Davon, und von der Tabellenart hängt die Art des internen Tabellenzugriffes ab. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -3- Kapitel 6 Tabellenarten: Es gibt drei Arten von internen Tabellen bei ABAP. 1. 2. 3. Standart-Tabellen Sortierte-Tabellen Hash-Tabellen Die Unterschiede zwischen den Tabellenarten sind im wesentlichen in der Art und Weise des Zugriffes und in der internen Verwaltung zu finden. Bei Standard-Tabellen wird intern ein linearer Index verwaltet. Ab einer bestimmten Größe wird dieser zu einem Baum, um die Zugriffszeit zu verkürzen. Man kann jedoch neben dem Index auch über den Schlüssel auf die Inhalte der Tabelle zugreifen. In diesem Fall wächst die Zugriffszeit linear mit zunehmender Größe der Tabelle. Der Schlüssel einer Standard-Tabelle ist immer NON-UNIQUE! Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -4- Kapitel 6 Standard-Tabellen sind meist dann von Vorteil, wenn der Inhalt über den Index angesprochen werden soll. Dies ist die schnellste Möglichkeit, an die Einträge zu kommen. Der Zugriff über den Schlüssel ist nur dann sinnvoll, wenn das Füllen der Tabelle unabhängig von der restlichen Verarbeitung ist. Bei Sortierten-Tabellen ist es dem Nutzer freigestellt ob der Schlüssel eindeutig ist oder nicht. Auch bei diesen Tabellen wird intern ein Index gepflegt. Deshalb werden Standard-Tabellen und sortierte Tabellen auch als Index-Tabellen bezeichnet. Der Zugriff auf die Tabelleninhalte erfolgt hier mittels binärer Suche, deren Aufwand logarithmisch ist. Die Sortierung erfolgt aufsteigend nach dem Tabellenschlüssel. Tabellen dieser Art werden immer dann benötigt, wenn Daten schon am Anfang sortiert vorliegen müssen. Der Zugriff auf Hash-Tabellen wird, mit einem Hash-Algorithmus vorgenommen. Dabei ist die Zugriffszeit immer gleich, unabhängig von der Größe der Tabelle. Der Schlüssel bei dieser Tabellenart muss immer eindeutig sein, denn es gibt keinen internen Index. Daher sind diese Tabellen dort am besten geeignet, wo Schlüsselzugriffe die zentrale Operation darstellen. Hash-Tabellen sind besonders für grosse Datenmengen geeignet, da sie vom Aufbau her den externen Tabellen aus den Datenbanken am ähnlichsten sind. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -5- Kapitel 6 Hier soll der Umgang mit internen Tabellen näher erläutert werden. Es wird gezeigt, wie man Tabellen anlegt, mit Daten füllt, manipuliert und wieder ausgibt. Anlegen interner Tabellen: Interne Tabellen können entweder zuerst als Typ deklariert werden (und im Laufe des Programms kann darauf basierend ein Datenobjekt erstellt werden), oder man definiert sie direkt als vollständig spezifiziertes Datenobjekt. Hier ein Beispiel zum Anlegen eines Tabellentyps: TYPES : BEGIN OF zeilentyp, spalteeins TYPE I, spaltezwei TYPE I, spaltedrei TYPE I, END OF zeilentyp. TYPES Tabellentyp TYPE STANDARD TABLE OF zeilentyp WITH DEFAULT KEY. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -6- Kapitel 6 Zuerst wird der Zeilentyp definiert, also die Spalten, die die Tabelle enthalten soll. In der zweiten TYPES-Anweisung wird dann der eigentliche Tabellentyp definiert. Diese Tabelle ist eine StandardTabelle mit einem Standard-Schlüssel. Nun kann im weiteren Verlauf des Programms dieser Typ verwendet werden, um entsprechende Datenobjekte zu erstellen. Ist der Tabellentyp definiert, kann nun das Datenobjekt dazu erstellt werden. Syntax: DATA Tabellenobjekt TYPE Tabellentyp. Es wird ein Tabellenobjekt vereinbart, das vom Typ "Tabellentyp" ist (aus dem Beispiel oben). Zusätzlich kann noch ein Tabellenkopf deklariert werden. Das geschieht mit dem Schlüsselwort WITH HEADER LINE. Dieser dient als eine Art Arbeitsbereich und kann das Arbeiten mit den Tabellen leichter machen. Nachteil ist, dass der Code dadurch unverständlicher wird. Es wird deshalb empfohlen, auf diesen Zusatz zu verzichten. Syntax: TYPES <tabname> TYPE <Tabellentyp> OF <Zeilentyp> WITH <Schlüssel> Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -7- Kapitel 6 Für Tabellentyp gibt es die Möglichkeiten: - STANDARD TABLE SORTED TABLE und HASHED TABLE Der Zeilentyp muss natürlich vorher definiert worden sein. Bei der Angabe des Schlüssels gibt es auch mehrere Möglichkeiten: - - UNIQUE DEFAULT KEY: Es wird ein eindeutiger Standardschlüssel definiert. NON UNIQUE DEFAULT KEY: Der Standardschlüssel ist nicht eindeutig. KEY <Spalten> - Benutzerdefinierter Schlüssel wird definiert, es können mehrere Spalten angegeben werden, UNIQUE/NON UNIQUE kann davor gesetzt werden. KEY TABLE_LINE: Die gesamte Zeile wird zum Schlüssel, geeignet für Tabellen mit elementarem Zeilentyp. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -8- Kapitel 6 Zusätzlich kann der Tabelle noch ein initialer Speicherbedarf mitgegeben werden. Mit dem Schlüsselwort INITIAL SIZE <n> wird für <n> Zeilen Speicherplatz reserviert. Wird diese Anzahl im Laufe des Programms überschritten, so wird noch einmal das doppelte der initialen Reservierung freigestellt. Im nächsten Beispiel erfolgt die direkte Definition einer Tabelle als Datenobjekt. DATA Tabelle TYPE HASHED TABLE OF Zeilentyp WITH UNIQUE KEY spalteeins. Es wird eine Variable "Tabelle" vereinbart, die eine interne Tabelle ist. Der Tabellentyp ist Hash und der Zeilentyp bezieht sich auf den Typ "Zeilentyp" im ersten Beispiel. Da bei Hash-Tabellen der Schlüssel immer UNIQUE sein muss, ist er im Beispiel entsprechend definiert worden. Tabellen die in der DATA-Anweisung deklariert werden, müssen immer vollständig spezifiziert sein! Statt TYPES wird jetzt das Schlüsselwort DATA verwendet, sonst bleibt alles gleich. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 -9- Kapitel 6 Füllen der Tabelle: Wenn eine Tabelle mit Daten gefüllt werden soll, gibt die Möglichkeit Daten aus einer anderen Tabelle zu holen, oder die Daten von Hand einzupflegen. Begonnen wird mit der zweiten Variante. Zum Einfügen eines einfachen Datensatzes wird das Schlüsselwort INSERT verwendet. Hier ein Beispiel: INSERT Zeile INTO TABLE Tabelle. Die Variable "Zeile" muss vorher natürlich deklariert werden und ihr müssen Werte zugeordnet sein, (siehe SCO "Strukturen"). Die Struktur "Zeile" muss genauso aufgebaut sein wie der Zeilentyp der Tabelle. Bei Standard-Tabellen wird der Datensatz einfach angehängt, bei sortierten Tabellen wird der Datensatz nach den Schlüsselattributen einsortiert, so auch bei Hash-Tabellen. Syntax: INSERT <Zeile> INTO TABLE <Tabelle>. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 10 - Kapitel 6 Die andere Variante ist, die Tabelle mit Daten aus einer anderen, Hierzu ein Beispiel: kompatiblen Tabelle zu füllen. MOVE Tabelle1 TO Tabelle2. oder: Tabelle1 = Tabelle2. Wichtig ist, dass die Tabellen kompatibel, oder ineinander konvertierbar sind. Interne Tabellen sind konvertierbar, wenn ihre Zeilentypen konvertierbar sind. Die Konvertierbarkeit von internen Tabellen hängt nicht von der Anzahl der Zeilen ab. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 11 - Kapitel 6 Manipulieren von Tabelleninhalten: Die Manipulation von Zeilen einer Tabelle wird über das Schlüsselwort MODIFY realisiert. Es gibt die Möglichkeit einzelne Zeilen zu modifizieren, oder mehrere Zeilen mit Hilfe einer Bedingung zu verändern. Zuerst ein Beispiel zur Modifikation einer einzelnen Zeile. Zeile-Spalteeins = 10. Zeile-Spaltezwei = 20. Zeile-Spaltedrei = 30. MODIFY TABLE Tabelle1 FROM Zeile. Wichtig ist, dass die Struktur "Zeile" kompatibel zur Zeilenstruktur von "Tabelle1" ist. Über die Variable "Zeile" wird der entsprechende Eintrag in der Tabelle gefunden. Es wird der Eintrag genommen, bei dem der Inhalt des Feldes mit dem Schlüssel der Tabelle übereinstimmt. Ist z. B. "Spalteeins" der Schlüssel von Tabelle1, so wird die Zeile in der Tabelle gesucht, deren Spalteeins gleich 10 ist. Der Rest der Tabellenzeile wird dann mit den neuen Werten gefüllt. Syntax: MODIFY TABLE <Tabelle> FROM <Zeile> [TRANSPORTING <Spalten>]. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 12 - Kapitel 6 Zusätzlich kann noch angegeben werden, welche Spalten ersetzt werden sollen. Dadurch kann die Performance erhöht werden. Dieser Zusatz ist jedoch optional. Sollen mehrere Zeilen in einem Schritt manipuliert werden, so ist eine Bedingung anzugeben, die die zu ändernden Zeilen gemeinsam haben. Auch hier wird der Befehl MODIFY verwendet. Das Schlüsselwort TRANSPORTING ist hier jedoch Pflicht. Bei Standard-Tabellen können sogar Schlüsselattribute geändert werden. Hier ein Beispiel zum ändern mehrerer Zeilen. MODIFY Tabelle1 FROM Zeile TRANSPORTING Spaltezwei Spaltedrei WHERE Spalteeins < 100. Es werden die Werte der „Spaltezwei“ und „Spaltedrei“ in den Zeilen geändert, in denen die "Spalteeins" einen Wert hat, der kleiner als 100 ist. Das Schlüsselwort TABLE darf hier nicht verwendet werden, da mit dem Index gearbeitet wird! Sollen Zeilen einer Tabelle gelöscht werden, wird das Schlüsselwort DELETE verwendet. Dazu ein Beispiel. DELETE Tabelle1 WHERE Spalteeins < 100. DELETE TABLE Tabelle1 FROM Zeile. Es werden die Zeilen gelöscht, deren "Spalteeins" kleiner als 100 ist. In der zweiten Variante wird die Zeile gelöscht, deren Schlüsselfelder gleich denen der Struktur "Zeile" sind. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 13 - Kapitel 6 Syntax: DELETE TABLE <Tabelle> FROM <Zeile>. Die entsprechenden Spalten werden in diesem Fall über den Tabellenschlüssel selektiert. Soll ein Eintrag mit einem bestimmten Index gelöscht werden, so ändert sich die Syntax folgendermaßen: DELETE <Tabelle> INDEX <Index>. Sollen mehrere Zeilen mit Hilfe des Indexzugriffes gelöscht werden, so wird der Befehl entsprechend erweitert: DELETE <Tabelle> FROM <Index1> TO <Index2> WHERE <Bedingung>. Es werden die Zeilen zwischen dem Index1 und dem Index2 gelöscht, die einer Bedingung genügen. Wichtig: Beim Zugriff auf die Tabelle über den Index wird das Wort in der Anweisung TABLE weggelassen. Wird jedoch mit dem Schlüssel gearbeitet ist TABLE zu verwenden. Das gilt auch für alle anderen Befehle, die über den Index auf Tabellen zugreifen können. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 14 - Kapitel 6 Ausgabe: Um interne Tabellen am Bildschirm sichtbar zu machen, müssen sie zeilenweise gelesen werden. Am besten geht so etwas mit einer Schleife. Die entsprechende Anweisung ist LOOP AT. Innerhalb der Schleife kann dann eine WRITE-Anweisung folgen, sowie weitere beliebige Anweisungen. Die Schleife ist auch ein effizientes Mittel um Tabellen schnell zu füllen. Dies geschieht mit der INSERT-Anweisung im Schleifenkörper. Allerdings muss hier eine DO-Schleife verwendet werden. In nachfolgenden Beispiel wird eine Tabelle mit Zahlen gefüllt und anschließend ausgegeben. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 15 - Kapitel 6 Data n type i. n = 1. DO 3 TIMES. Zeile-Spalteeins = n. Zeile-Spaltezwei = n * 2. Zeile-Spaltedrei = n * 3. INSERT Zeile INTO TABLE Tabelle1. n = n + 1. ENDDO. LOOP AT Tabelle1 INTO Zeile. WRITE: / Zeile-Spalteeins, Zeile-Spaltezwei, Zeile-Spaltedrei. SUM. ENDLOOP. uline. WRITE: / Zeile-Spalteeins, Zeile-Spaltezwei, Zeile-Spaltedrei. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 16 - Kapitel 6 Zusätzlich wird noch die Summe aller Spalten berechnet. Der Ausgabebildschirm sieht dann wie folgt aus. Syntax: LOOP AT <Tabelle> INTO <Struktur>|ASSIGNING <Feldsymbol> [WHERE <Bedingung>]. <Anweisungsblock> ENDLOOP. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 17 - Kapitel 6 Mit ASSIGNING wird nicht die ganze Zeile ausgelesen, sondern einem vorher definierten Feldsymbol wird die Zeile des aktuellen Schleifendurchlaufes zugewiesen, d.h. das Feldsymbol zeigt immer auf die aktuelle Zeile. Es werden nur die Zeilen bearbeitet, die der WHERE-Bedingung entsprechen (diese ist optional). Schleifen können geschachtelt werden, so auch die LOOP-Schleife. Dies geschieht vor allem bei der Gruppenstufenverarbeitung. Als Gruppen werden gleiche Inhalte einer Spalte bezeichnet. Auf diese Weise kann eine Gruppenstufenhierarchie entstehen. Das erste Feld steht in der Hierarchie am höchsten. Die Hierarchie entsteht dadurch, dass die Tabelle entsprechend der Reihenfolge ihrer Spalten sortiert sind. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 18 - Kapitel 6 Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 19 - Kapitel 6 Mit dem Befehl AT / ENDAT innerhalb einer LOOP-Anweisung kann auf Gruppenstufen reagiert werden. Syntax: LOOP AT <Tabelle>. AT FIRST.... ENDAT. AT NEW <Spalte x>....... ENDAT. AT NEW <Spalte y>....... ENDAT. ....... <Normale Verarbeitung ohne Gruppenstufen> ....... AT END OF <Spalte y>.... ENDAT. AT END OF <Spalte x>.... ENDAT. AT LAST..... ENDAT. ENDLOOP. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 20 - Kapitel 6 REPORT ytu_mgro_ausgabe . *Vereinbarung des Zeilentyps TYPES: BEGIN OF tabelle, spalteeins TYPE spaltezwei TYPE spaltedrei TYPE spaltevier TYPE END OF tabelle. i, i, i, i, *Vereinbarung des Tabellentyps DATA tab TYPE SORTED TABLE OF tabelle WITH NON-UNIQUE KEY spalteeins. *Vereinbarung des eingentlichen Tabellenobjektes DATA: x TYPE tabelle, y1 TYPE i, y2 TYPE i, y3 TYPE i. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 21 - Kapitel 6 *… *Füllen der Tabelle y1 = 1110. y2 = 1100. y3 = 1000. x-spalteeins = 1000. DO 2 TIMES. y3 = y3 + 100. x-spaltezwei = y3. DO 3 TIMES. y2 = y2 + 10. x-spaltedrei = y2. DO 4 TIMES. y1 = y1 + 1. x-spaltevier = y1. INSERT x INTO TABLE tab. ENDDO. ENDDO. ENDDO. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 22 - Kapitel 6 *… *Ausgeben der Tabelle. LOOP AT tab INTO x. WRITE: / x-spalteeins, x-spaltezwei, x-spaltedrei, x-spaltevier. ENDLOOP. SKIP. SKIP. *Ausgeben nach Gruppenstufen WRITE / 'Einzelsatz nach Spalte 2:'. LOOP AT tab INTO x. AT NEW spaltezwei. ENDAT. WRITE: / x-spalteeins, x-spaltezwei, x-spaltedrei, x-spaltevier. AT END OF spaltezwei. ULINE. ENDAT. ENDLOOP. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 23 - Kapitel 6 *… SKIP. WRITE / 'Einzelsatz nach Spalte 3:'. LOOP AT tab INTO x. AT NEW spaltedrei. ENDAT. WRITE: / x-spalteeins, x-spaltezwei, x-spaltedrei, x-spaltevier. AT END OF spaltedrei. ULINE. ENDAT. ENDLOOP. Zuerst wird eine Tabelle so mit Zahlen gefüllt, dass eine Gruppenstufenverarbeitung möglich ist. Diese Tabelle wird am Anfang einfach ausgegeben. Nun beginnt die Gruppenstufenverarbeitung. In der ersten Variante wird nach der ersten Hierarchiestufe unterschieden. Es ergeben sich zwei Teiltabellen (getrennt durch eine horizontale Linie). In der zweiten Variante wird nach der zweiten Stufe unterschieden. Es gibt nun sechs Teiltabellen. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 24 - Kapitel 6 Befehle auf interne Tabellen: Befehl Erläuterung Sortiert Tabellen nach ihrem Schlüssel aufsteigend oder absteigend. Standardmäßig SORT <Tabelle> [ASCENDING|DESCENDING] wird aufsteigend sortiert. Soll Text sortiert werden, so ist der Zusatz AS TEXT anzufügen. STABLE heißt, dass die Reihenfolge von Zeilen mit gleichem Schlüssel [AS TEXT] [STABLE]. unverändert bleibt. CLEAR <Tabelle> REFRESH <Tabelle> FREE <Tabelle>. Alle drei Befehle können eine Tabelle initialisieren, d.h. sie geben den für die Tabelle benötigten Speicherplatz frei. Mit CLEAR kann auch auf den Tabellenkopf zugegriffen werden. REFRESH dagegen greift nur auf den Tabellenkörper zu. Bei beiden Befehlen bleibt der initiale Speicherbedarf reserviert, sofern einer definiert wurde. Der Befehl FREE dagegen gibt alles frei. Auch hier wird nur auf den Tabellenkörper zugegriffen. Die Tabelle existiert aber weiterhin. Sie belegt jedoch nur noch Speicherplatz für den Tabellen-Header. READ TEABLE <Tabelle> FROM <StrukturA> INTO <StrukturB> [COMPARING <Spalte>]. Mit READ kann eine Zeile einer Tabelle ausgelesen werden. "StrukturA" ist dabei das Selektionmerkmal und "StrukturB" ist die Zielstruktur. Beide sollten zum Zeilentyp der Tabelle kompatibel sein. Der Zusatz COMPARING vergleicht den ausgelesen Datensatz mit dem Inhalt der Zielstruktur, bevor der Transport erfolgt. Das Ergebnis wird in der Systemvariable SY-SUBRC gespeichert. Sind die Inhalte gleich, so ist der Wert Null, sind sie ungleich ist er Zwei, und wird kein entsprechender Eintrag gefunden, so ist der Wert Vier. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 25 - Kapitel 6 Befehl Erläuterung DESCRIBE TABLE <Tabelle> Mit diesem Befehl kann man sich eine detailierte Beschreibung einer Tabelle [LINES <Anzahl>] [OCCURS anfertigen lassen. In der Variable "Anzahl" wird die Anzahl der aktuell vorhandenen Zeilen gespeichert. "Initial" enthält die beim Anlegen der Tabelle angegebene initiale <Initial>] [KIND <Art>]. Grösse. In "Art" ist die Art der Tabelle gespeichert, wobei "T" für Standard steht, "S" für Sortiert und "H" für Hash. APPEND <Zeile> TO <Tabelle> [SORTED BY <Spalte>]. oder APPEND LINES OF <TabelleA> [FROM <IndexX> TO <IndexY>] TO <TabelleB>. Zeilen werden an die Tabelle angehängt. In der ersten Variante kommt eine einzelne Zeile dazu. Der Zusatz SORTED BY bewirkt, dass eine Art Rangliste erstellt wird, d.h. die Tabelle wird absteigend nach der angegebenen Spalte sortiert (geht nur, wenn die Tabelle leer ist). Die zweite Variante bewirkt, dass mehrere Zeilen der "TabelleA" an die "TabelleB" angehängt werden. Zusätzlich kann noch eine Indexspanne angegeben werden. Zu beachten ist, dass dieser Befehl nur auf Index-Tabellen anwendet werden kann! Es soll nun ein Beispiel folgen, in dem die in der Tabelle aufgeführten Befehle angewendet werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 26 - Kapitel 6 REPORT ytu_mgro_ausgabe2. *Vereinbarung des Zeilentyps TYPES: BEGIN OF student, name(10) TYPE c, vorname(10) TYPE c, matrikel TYPE i, note TYPE i, END OF student. *Vereinbarung des Tabellentyps DATA tab_student TYPE SORTED TABLE OF student WITH UNIQUE KEY matrikel INITIAL SIZE 10. *Vereinbarung des eingentlichen Tabellenobjektes DATA s TYPE student. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 27 - Kapitel 6 *… *Füllen der Tabelle s-name = 'Meier'. s-vorname = 'Susann'. s-matrikel = 2000. s-note = 2. INSERT s INTO TABLE tab_student. s-name = 'Meier'. s-vorname = 'Daniel'. s-matrikel = 2200. s-note = 1. INSERT s INTO TABLE tab_student. s-name = 'Müller'. s-vorname = 'Konrad'. s-matrikel = 2002. s-note = 4. INSERT s INTO TABLE tab_student. s-name = 'Schulze'. s-vorname = 'Otto'. s-matrikel = 2020. s-note = 1. INSERT s INTO TABLE tab_student. s-name = 'Richter'. s-vorname = 'Edeltraut'. s-matrikel = 2222. s-note = 3. INSERT s INTO TABLE tab_student. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 28 - Kapitel 6 *… *Ausgeben der Tabelle (mit Errechnung eines Durchschnittes): DATA: x TYPE i, d decimals 2 TYPE p. x = 0. LOOP AT tab_student INTO s. WRITE: / s-matrikel, s-name, s-vorname, s-note. SUM. x = x + 1. ENDLOOP. d = s-note / x. WRITE: / 'Durchschnitt:', d. *Auslesen einer Zeile mit READ SKIP. s-matrikel = 2000. READ TABLE tab_student FROM s INTO s. WRITE: /'Gefundener Student zum Matrikel:', s-matrikel,' ist: ', s-name, s-vorname. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 29 - Kapitel 6 *… *übertragen der Tabelle auf eine Andere und Sortierung nach Noten SKIP. DATA tab_student_a TYPE STANDARD TABLE OF student INITIAL SIZE 20. MOVE tab_student TO tab_student_a. SORT tab_student_a BY note. LOOP AT tab_student_a INTO s. WRITE: / s-matrikel, s-name, s-vorname, s-note. ENDLOOP. *Ausgabe des Tabellenattribute beider Tabellen SKIP. DATA: k TYPE c, l TYPE i, i TYPE i. DESCRIBE TABLE tab_student LINES l OCCURS i KIND k. WRITE: / 'Tab_Student: ', 'Tabellentyp:', k, ' Initial Size:',i, 'Anzahl der Zeilen:', l. DESCRIBE TABLE tab_student_a LINES l OCCURS i KIND k. WRITE: / 'Tab_Student: ', 'Tabellentyp:', k, ' Initial Size:',i, 'Anzahl der Zeilen:', l. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 30 - Kapitel 6 *… *Anhängen neuer Datensätze mit APPEND SKIP. s-name = 'Kunze'. s-vorname = 'Yvonne'. s-matrikel = 2242. s-note = 1. APPEND s TO tab_student_a . LOOP AT tab_student_a INTO s. WRITE: / s-matrikel, s-name, s-vorname, s-note. ENDLOOP. *… Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 31 - Kapitel 6 *… *Initialisierung der Tabelle mit REFRESH und FREE SKIP. REFRESH tab_student. DESCRIBE TABLE tab_student LINES l OCCURS i KIND k. WRITE: / 'Tab_Student: ', 'Tabellentyp:', k, ' Initial Size:',i, 'Anzahl der Zeilen:', l. tab_student = tab_student_a. DESCRIBE TABLE tab_student LINES l OCCURS i KIND k. WRITE: / 'Tab_Student: ', 'Tabellentyp:', k, ' Initial Size:',i, 'Anzahl der Zeilen:', l. FREE tab_student. DESCRIBE TABLE tab_student LINES l OCCURS i KIND k. WRITE: / 'Tab_Student: ', 'Tabellentyp:', k, ' Initial Size:',i, 'Anzahl der Zeilen:', l. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 32 - Kapitel 6 In diesem Beispiel wird eine Tabelle definiert und dann mit Daten gefüllt. Bei der Ausgabe wird die Summe aller Spalten berechnet. Allerdings ist in diesem Fall nur die Summe der Spalte "Note" sinnvoll. Anschließend wird eine bestimmte Zeile mit READ selektiert und ausgegeben. Um diese Tabelle nach den Noten zu sortieren, muss sie erst in eine andere Tabelle übertragen werden. Grund dafür ist, dass man Tabellen die vom Typ "Sorted Table" sind, nicht nach einem anderen Attribut als dem Schlüssel sortieren kann. Daher ist die neue Tabelle eine Standard-Tabelle. Nun kann der Sort-Befehl angewendet werden. Im nächsten Programmteil werden die Attribute beider Tabellen ausgegeben. Danach wird an die Standard-Tabelle ein weiterer Datensatz angehängt. Das geht bei Sortierten Tabellen nicht. Am Ende wird die erste Tabelle mit zwei verschiedenen Varianten initialisiert. Es werden jeweils die Attribute ausgegeben. Nach dem letzten recht umfangreichen Beispiel sollte es Ihnen gut möglich sein, mit internen Tabellen zu arbeiten. Der wesentliche Nutzen solcher Tabellen liegt jedoch in der temporären Speicherung von Daten aus externen Datenbanktabellen. Dieses Thema wird ausführlich in der Lerneinheit Arbeiten mit externen Tabellen behandelt. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 33 - Kapitel 6 Aufgaben: 1. Erstellen Sie eine interne Tabelle, die die Spalten Name, Vorname und Telefonnummer enthält. Tragen Sie einige Werte ein und geben Sie die Tabelle anschließend aus. Ordnen Sie diese nach Namen und erzeugen Sie wiederum eine Ausgabe. 2. Erweitern Sie das in der letzten Aufgabe erstellte Programm und erweitern sie es dahingehend, dass Sie nach Eingabe eines Namens die dazugehörige Telefonnummer bekommen. 3. Definieren Sie eine Tabelle, die einem Notenspiegel entspricht. Tragen Sie einige Daten ein. Lassen Sie sich den Durchschnitt errechnen. Ändern Sie einige Datensätze ab (mit Modify) und errechnen Sie den Durchschnitt neu. 4. Definieren Sie eine Tabelle, die einem Notenspiegel entspricht und auch das Jahr, in dem Sie die Note erhalten haben speichern kann. Tragen sie einige Datensätze ein und lassen Sie sich die Tabelle geordnet nach Jahren ausgeben. Verwenden Sie hierzu die Gruppenstufenverarbeitung. Lassen Sie sich den Durchschnitt pro Jahr errechnen. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit internen Tabellen Kapitel 4 Kapitel 5 - 34 - Kapitel 6 Arbeiten mit externen Tabellen In diesem Kapitel soll der Umgang mit Datenbanktabellen erlernt werden. Daten sollen herausgelesen und in ansprechender Form und Menge auf dem Bildschirm ausgegeben werden. Dazu gehört, dass man nur bestimmte Zeilen 'selektiert' und nicht die gesamte Tabelle ausgibt. Ein weiteres Thema ist die Verknüpfung von mehreren Tabellen. Das alles soll mit Hilfe der Datenbanksprache OpenSQL realisiert werden. Wie mit ihr umzugehen ist, soll nun zum Thema werden. Um jedoch mit externen Tabellen arbeiten zu können, muss man wissen, wie sie heißen, und wie sie aufgebaut sind. Diese Informationen erhält man aus dem SAP-Dictionary. Deshalb soll zu Beginn dieser Einheit ein Exkurs zum Umgang mit dem Dictionary gemacht werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -1- Kapitel 6 Das ABAP Dictionary: Die richtige Tabelle finden: Das ABAP-Dictionary enthält die Beschreibung aller im System enthaltenen Tabellen. In SAP werden die Tabellen u.a. durch ihren Namen und ihre Kurzbeschreibung definiert. Wird also eine bestimmte Tabelle gesucht, so geschieht das über diese beiden Merkmale. Es gibt natürlich weitere Merkmale, aber im Rahmen dieses Kurses sind die eben genannten ausreichend. Um das ABAP-Dictionary zu starten, verwenden Sie entweder den entsprechenden Menüeintrag im Easy-Access-Menü, oder den Transaktionscode SE11. Der nun folgende Bildschirm zeigt alle Objekte die vom Dictionary verwaltet werden. Uns interessieren derzeit nur die Datenbanktabellen. Gibt man hier den Tabellennamen ein, wird dem Nutzer der Aufbau der Tabelle angezeigt. Oft ist es so, dass Sie den Namen der Tabelle nicht oder nur teilweise kennen. Setzt man den Cursor in das Eingabefeld und drückt die Taste F4, bekommt man die Suchhilfe für Tabellen. Man kann hier nach dem Namen suchen, oder nach der Kurzbeschreibung. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -2- Kapitel 6 Zu beachten ist, dass man immer nur nach einem Merkmal (entweder Name oder Kurzbeschreibung) suchen kann, und dass bei der Kurzbeschreibung zwischen Groß- und Kleinschreibung unterschieden wird. Der Stern (*) als Wildcard kann bei beiden Suchkriterien verwendet werden. Ist die Suche erfolgreich verlaufen, bekommt die Namen der Tabellen angezeigt, die den Suchkriterien entsprechen, man kann sich dann die richtige mit einem Doppelklick heraussuchen. Der Name wird dann in das Eingabefeld eingetragen und mit einem Klick auf anzeigen kommt man auf den Bildschirm "Tabelle anzeigen". Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -3- Kapitel 6 Daten der Tabelle lesen. Auf den ersten Blick sieht der Bildschirm sehr komplex aus. Davon sollten SIe sich aber nicht verwirren lassen. Als erstes sollten Sie sich über das klar werden, was hier angezeigt wird. Hier wird nicht der Inhalt der Tabelle angezeigt, sondern die Struktur der Tabelle, also die Spalten aus denen sie besteht. Jede Zeile beschreibt eine Spalte der Tabelle. (In SAP werden die Spalten als Felder bezeichnet.) Jede Spalte hat einen Namen, einen Datentyp (genau so wie bei internen Tabellen) eine eigene Kurzbeschreibung sowie Flags, die anzeigen ob die Spalte zum Schlüssel der Tabelle gehört oder nicht. Wenn Sie später mit ihrem ABAP-Programm bestimmte Daten aus dieser Tabellen holen wollen, müssen Sie wissen, welche Datentypen die Tabelle verwendet, denn Sie werden die gleichen verwenden, da es sonst zu Kompatibilitätsproblemen kommt. Lassen Sie also diesen Modus offen und starten Sie einen neuen um darin Ihr Programm zu schreiben, so haben Sie die Daten Ihrer Tabelle immer griffbereit. Im ABAP-Programm gibt es zwei Möglichkeiten Datenobjekte mit dem richtigen Datentyp zu deklarieren. Man kann entweder eine Struktur definieren die alle Spalten der Tabelle enthält, oder man nimmt nur einzelne Spalten her und definiert sich entsprechende Datenobjekte dazu. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -4- Kapitel 6 Die erste Möglichkeit sieht so aus. DATA <meineStruktur> TYPE <Tabellenname> Und die zweite so. DATA <meinDatenobekt> TYPE <Tabellenname-Spalte> Wie man die Daten aus der Tabelle holt wird im folgenden Abschnitt gezeigt. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -5- Kapitel 6 Die Select-Anweisung: Selektieren von Zeilen: Die SELECT-Anweisung ist der Grundbefehl um Daten aus Datenbanktabellen zu 'selektieren'. Der Anweisung muss der Name der Tabelle mitgeteilt werden, also die Angaben darüber, welche Daten benötigt werden, sowie die Struktur, in die die selektierten Daten gespeichert werden können. Sind diese Parameter bekannt, so kann eine erste einfache SELECT-Anweisung formuliert werden. DATA s TYPE makt. SELECT * INTO s FROM makt UP TO 4 ROWS. WRITE: / s-matnr, s-maktx. ENDSELECT. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -6- Kapitel 6 In diesem Beispiel werden aus der Tabelle MAKT alle Spalten bis zur vierten Zeile selektiert. Diese Zeilen werden in s gespeichert, einem vorher definierten Datenbereich, der dem Zeilentyp der Tabelle entspricht. Die Spalten der Tabelle werden dann am Bildschirm ausgeben. DATA s TYPE makt. SELECT maktx INTO CORRESPONDING FIELDS OF s FROM makt UP TO 4 ROWS. WRITE: / s-matnr, s-maktx. ENDSELECT. Eine SELECT-Anweisung ist, wie man am Beispiel gut sehen kann, eine Schleife (SELECT ... ENDSELECT). Sie geht zeilenweise durch die gegebene Tabelle und speichert bestimmte Zeilen und Spalten in ein Strukturobjekt. Um nur bestimmte Spalten zu selektieren, werden statt dem Stern '*' nun die gewünschten Spalten angegeben. Das kann viel Rechenzeit sparen, wenn nicht alle Spalten benötigt werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -7- Kapitel 6 Es wird nun nur die Spalte 'maktx' selektiert und in das entsprechende Feld des Arbeitsbereiches s geschrieben. Die WRITE-Anweisung kann jetzt nur eine Spalte ausgeben, da 's-matnr' keine Werte enthält. Fehlt der Zusatz CORRESPONDING FIELDS OF s wird der selektierte Wert einfach in das erste Feld der Struktur 's' geschrieben. Da die Typen der Felder meist nicht übereinstimmen, kann in diesem Fall keine korrekte Ausgabe erfolgen. Nach dem Aussuchen der richtigen Spalten sollen nun auch die richtigen Zeilen selektiert werden. Dazu muss eine Bedingung angegeben werden, nach der die Zeilen ausgesucht werden sollen. Eine Bedingung ist einem logischen Ausdruck sehr ähnlich, richtet sich jedoch nach der SQL-Syntax. DATA s TYPE makt. SELECT * INTO s FROM makt WHERE matnr LIKE 'TU00%'. WRITE: / s-matnr, s-maktx. ENDSELECT. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -8- Kapitel 6 Einer Bedingung wird immer das Schlüsselwort WHERE vorangestellt. In diesem Beispiel werden alle Zeilen selektiert, deren Spalte 'matnr' mit "TU00" beginnt (Das Prozentzeichen ("%")ist hier eine Art Wildcard, siehe Tabelle). Hinter der WHERE-Anweisung können noch folgende Arten von Bedingungen stehen. Bedingung Erklärung <Spalte> <operator> Es wird ein Vergleich angestellt. Folgende Operatoren sind u.a. möglich: =, <>,<,>, <=, =>. Die <Wert> Anwendung dieser Operatoren bei Zeichenketten (Strings) wird nicht empfohlen. Angabe eines Intervalls: Die Bedingung ist Wahr, wenn der Wert der Spalte [nicht] zwischen <Spalte> [NOT] BETWEEN <WertA> den angegebenen Werten liegt. Auch hier ist Vorsicht geboten, wenn dieses auf Text angewendet werden soll. AND <WertB> Hier wird ein Wertevergleich vorgenommen. Die Werte, die in der entsprechenden Spalte <Spalte> IN (<Wert1>, <Wert2>, vorhanden sein sollen, können hier explizit angegeben werden. Diese Variante kann auch mit Zeichenketten genutzt werden. <Wert3>, ..., <Wertn>) Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 -9- Kapitel 6 Bedingung Erklärung <Spalte> IS [NOT] NULL Es wird überprüft, ob die Spalte einen Null-Wert enthält. <Spalte> LIKE <Zeichenkette> Es kann, wie im Beispiel gesehen, eine Zeichenkette als Bedingung benutzt werden. Dabei sind die Platzhalter '_' und '%' erlaubt. Das Prozentzeichen hält Platz für beliebig viele Zeichen und der Unterstrich hält Platz für genau ein Zeichen. <Spalte> <BedingungA> AND|OR <BedingungB> Es besteht die Möglichkeit mehrere Bedingungen der oben genannten Art anzugeben und diese miteinander zu verknüpfen. Die AND-Verknüpfung bedeutet, dass beide Bedingungen müssen wahr sein müssen, damit die Spalte selektiert wird. Wenn nur eine Bedingung benötigt wird, kann die OR-Verknüpfung genutzt werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 10 - Kapitel 6 Soll die Ausgabe in einer bestimmten Weise geordnet werden, so kann dies in der SELECT-Anweisung angegeben werden. Wenn die Ausgabe nach dem Primärschlüssel geordnet sein soll, so ist an die SELECT-Anweisung ein ORDER BY PRIMARY KEY anzufügen. Sollen andere Spalten die Reihenfolge bestimmen, so ergibt sich die Syntax wie folgt. Syntax: SELECT ... ORDER BY <Spalte1> [ASCENDING|DESCENDING] <Spalte2> [ASCENDING|DESCENDING] ... <SpalteN> [ASCENDING|DESCENDING]. Man kann zu jeder Spalte angeben, ob aufsteigend oder absteigend geordnet werden soll. Ohne Angabe der Reihenfolge wird aufsteigend sortiert. Die Priorität hängt dabei von der Reihenfolge ab. Mit diesem Grundwissen sollte es Ihnen möglich sein, einfache Abfragen zu gestalten. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 11 - Kapitel 6 Komplexere Abfragen: Gruppierung mit GROUP BY: Wenn viele Zeilen den gleichen Inhalt haben, kann es günstig sein, diese Zeilen zu einer Zeile zusammenzufassen und die Spalten in einer aggregierten Form darzustellen. Genau das bewirkt die GROUP BY-Klausel. DATA s TYPE makt. SELECT mandt MAX( matnr ) MIN( maktx ) INTO (s-mandt, s-matnr, s-maktx) GROUP BY mandt. WRITE: / s-mandt, s-matnr, s-maktx. ENDSELECT. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 12 - Kapitel 6 In diesem Beispiel wird nach der Spalte 'mandt' gruppiert. Da diese in der Tabelle immer den gleichen Wert hat, wird nur eine Zeile ausgegeben. Wichtig ist, dass alle Spalten die verwendet werden, explizit in der SELECT-Anweisung angegeben werden müssen. Der Stern (*) ist also nicht erlaubt. Auch die Zielstruktur muss voll ausformuliert werden, da sonst eine Fehlermeldung ausgegeben wird. Wichtig ist weiterhin, dass alle Spalten, nach denen nicht gruppiert wird, die aber mit ausgegeben werden sollen, in aggregierter Form angegeben sein müssen. Im Beispiel wurde einmal MAX und das andere mal MIN verwendet. Weitere Möglichkeiten einer Aggregation sind: AVG, SUM und COUNT. Gibt es immer noch zu viele Zeilengruppen, können diese mit Hilfe der HAVING-Klausel weiter eingeschränkt werden. HAVING arbeitet wie die WHERE-Klausel, darf jedoch nur hinter GROUP BY eingesetzt werden. Das oben genannte Beispiel wird dazu nur geringfügig erweitert. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 13 - Kapitel 6 DATA s TYPE makt. SELECT mandt MAX( matnr ) MIN( maktx ) INTO s FROM makt GROUP BY mandt HAVING MAX( matnr ) > 1000. WRITE: / s-mandt, s-matnr, s-maktx. ENDSELECT. Durch den HAVING-Zusatz werden die aggregierten Zeilen nur angezeigt, wenn es innerhalb der untersuchten Gruppe von 'mandt' in der Spalte 'matnr' mindestens eine Zeile gibt, deren Wert grösser als 1000 ist. Soviel zum Thema Gruppierung. Nun zur Verarbeitung mehrerer Tabellen. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 14 - Kapitel 6 Mehrere Tabellen verknüpfen: Sollen mehrere SELECT-Anweisung miteinander verknüpft werden, so ist eine Schachtelung nötig. In der Bedingung, also hinter WHERE, kommt ein weiteres SELECT. Es werden dann nur die Zeilen ausgegeben, bei denen das interne SELECT ein Ergebnis hatte. DATA s TYPE makt. SELECT * INTO s FROM makt WHERE EXISTS ( SELECT * FROM marm WHERE matnr = makt~matnr AND meinh = 'PAL' ). WRITE: / s-matnr, s-maktx . ENDSELECT. Im Beispiel werden die Tabellen 'makt' und 'marm' miteinander verknüpft. Dabei werden nur die Zeilen der Tabelle 'makt' ausgegeben, deren Spalte 'matnr' der Spalte 'matnr' in der Tabelle 'marm' entspricht und der Wert der Spalte 'meinh' gleich 'PAL' ist. Zuerst wird der innere Select ausgeführt und danach der äußere durchgeführt. Dabei werden nur die Zeilen ausgegeben, bei denen das innere Select zu einem Ergebnis gekommen ist (Schlüsselwort EXISTS). Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 15 - Kapitel 6 Weitere Möglichkeiten für Subquerys (Unterabfragen) sind: - - - WHERE <Spalte> [NOT] IN <Subselect>.: Es wird überprüft, ob der Wert einer Spalte in den selektierten Werten der Unterabfrage enthalten ist. Wichtig ist, dass die Unterabfrage nur eine Spalte abfragt, da es sonst zu einer Fehlermeldung kommt. WHERE <Spalte> <operator> <Subselect>.: Hier wird ein einfacher Vergleich vorgenommen. Als Operatoren können die gängigen Vergleichsoperatoren genommen werden. Das Subselect darf nur einzeilig sein, da sonst ein Vergleich nicht möglich ist und es zu einem Laufzeitfehler kommt. WHERE <Spalte> <operator> ALL|ANY|SOME <Subselect>.: Auch hier wird ein Vergleich mittels bestimmter Operatoren vorgenommen. Jedoch kann in diesem Fall das Subquery auch mehrzeilig sein. Mit dem Schlüsselwort ALL wird die Bedingung wahr, wenn der Vergleich in allen Zeilen positiv ausging. Bei ANY oder SOME muss mindestens ein Vergleich ein positives Ergebnis bringen, damit die Bedingung wahr ist. Eine weitere Möglichkeit Abfragen miteinander zu verknüpfen ist der Join. Dieser hat den Vorteil, dass man nun auch den Inhalt der anderen Tabelle einsehen kann. Dies war bei Subselects nicht möglich. Beim Join werden beide Tabellen in der FROM-Klausel angegeben. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 16 - Kapitel 6 Es sollte darauf geachtet werden, dass bestimmte Spalten (meist die Primärschlüssel) verglichen werden, da sonst keine Zuordnung stattfinden kann. Die Folge wäre, dass zu jeder Zeile der ersten Tabelle die zweite komplett ausgegeben würde! TYPES: BEGIN OF zeile, materialnr TYPE makt-matnr, kurztext TYPE makt-maktx, mengeneinheit TYPE marm-meinh, END OF zeile. DATA tab TYPE STANDARD TABLE OF zeile WITH NON-UNIQUE KEY materialnr. DATA s TYPE zeile. SELECT a~matnr a~maktx b~meinh INTO TABLE tab FROM makt AS a JOIN marm AS b ON a~matnr = b~matnr WHERE a~matnr LIKE 'TU00%'. LOOP AT tab INTO s. WRITE: / s-materialnr, s-kurztext, s-mengeneinheit. ENDLOOP. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 17 - Kapitel 6 In diesem Beispiel soll zusätzlich zu den Daten Materialnummer und Kurztext die Mengeneinheit mit ausgegeben werden. Diese Daten stehen jedoch in einer anderen Tabelle. Um die gesamten Daten anzuzeigen, ist ein Join nötig. Zuerst wird eine Struktur definiert, die die entsprechenden Datentypen enthält. Dazu kommen die Datenobjekte 'tab', eine interne Tabelle, und 's'. Beide können die Daten aus dem Select aufnehmen. Danach wird die eigentliche Selektion durchgeführt. Selektiert werden die Spalten matr und maktx aus der Tabelle makt und die Spalte meinh aus der Tabelle marm. Aus Gründen der Effizienz (Schreibaufwand) sind beide Tabellen mit einem Aliasnamen versehen worden (a und b). Nach der FROM-Anweisung und der Angabe der ersten Tabelle kommt das Schlüsselwort JOIN und die zweite Tabelle. Danach wird ein Vergleich der Schlüsselspalten vorgenommen, damit die Zeilen beider Tabellen einander zugeordnet werden können. Im Unterschied zu den bisherigen Selektionen wird dieses mal in eine interne Tabelle selektiert. Ein Vorgang der bei allen Selektionen möglich ist und durch die Anweisung ... INTO TABLE <Tabellenname> realisiert wird. Zum Schluss wird diese Tabelle ausgegeben. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 18 - Kapitel 6 Syntax: SELECT <Spalten> INTO <Struktur> FROM <TabelleA> [OUTER] JOIN <TabelleB> ON <Bedingung> Der Zusatz OUTER bewirkt einen Left Outer Join , dh. es werden auch die Zeilen der ersten Tabelle mit ausgegeben, bei denen es keine Ensprechung in der zweiten Tabelle gibt. Ohne den Zusatz werden solche Zeilen nicht ausgegeben (Inner Join). Die letzte Art SELECT-Anweisungen zu verknüpfen ist, eine Abfrage auf einer Datenbanktabelle mit einer Abfrage aus einer internen Tabelle zu verbinden. Die interne Tabelle dient dabei als "Behälter" für die Bedingungen, die für die zu selektierenden Zeilen der Datenbanktabelle zu gelten haben. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 19 - Kapitel 6 TYPES: BEGIN OF zeile, materialnr TYPE makt-matnr, kurztext TYPE makt-maktx, mengeneinheit TYPE marm-meinh, END OF zeile. DATA s TYPE zeile. DATA tab TYPE STANDARD TABLE OF marm. DATA t TYPE marm. SELECT * INTO TABLE tab FROM marm WHERE matnr LIKE 'TU00%'. SELECT matnr maktx INTO s FROM makt FOR ALL ENTRIES IN tab WHERE matnr = tab-matnr. WRITE: / s-materialnr, s-kurztext. ENDSELECT. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 20 - Kapitel 6 Zuerst wird eine interne Tabelle erstellt und mit Daten gefüllt. Diese Daten stammen aus der Tabelle 'marm'. Danach kommt der eigentliche Select. Dabei werden nur die Daten ausgelesen, deren Materialnummer auch in der internen Tabelle stehen. Damit ist die Einführung in OpenSQL beendet. Sie sollten jetzt in der Lage sein, Tabellen aller Art auszulesen und in gewünschter Form auszugeben. Das Anlegen und Modifizieren von Tabellen soll in diesem Rahmen nicht behandelt werden. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 21 - Kapitel 6 Aufgaben: 1. Selektieren Sie alle Werte der Tabelle 'marm' und geben Sie die Spalten 'matnr' und 'meinh' aus! 2. Ändern Sie oben gestellte Aufgabe so ab, das nur Datensätze ausgegeben werden, deren Spalten 'matnr' mit 'TU' beginnen. 3. Erweitern Sie das Programm so, dass zu jedem selektierten Datensatz aus der Tabelle 'makt' die Spalte 'maktx' ausgegeben wird. Verwenden Sie einen Join. 4. Modifizieren Sie ihr Programm ein weiteres mal. Lesen Sie das Ergebnis ihrer Selektion in eine interne Tabelle, sortieren Sie sie nach der Materialbezeichnung und geben Sie sie aus. Kapitel 1 Kapitel 2 Kapitel 3 Arbeiten mit externen Tabellen Kapitel 4 Kapitel 5 - 22 - Kapitel 6 Datenbearbeitung mit OpenSQL In Unternehmen existiert häufig nicht nur SAP-Datenbanken sondern auch SQL-Datenbanken. Nehmen wir z. B. einen Online-Shop, der die Daten der Bestellungen in einer SQL-Datenbank abspeichert und dann durch ein ABAP-Report auswertet und alle Bestellungen in das SAP-System integriert. Um einen derartigen Report so effizient wie möglich zu gestallten, müssen die folgende Grundregeln beachtet werden. 1. Die Treffermenge klein halten 2. Die zu übertragene Datenmenge klein halten 3. Die Anzahl der Datenbankzugriffe klein halten 4. Den Suchaufwand klein halten 5. Die generelle Datenbanklast klein halten Kapitel 1 Kapitel 2 Kapitel 3 Datenbearbeitung mit OpenSQL Kapitel 4 Kapitel 5 -1- Kapitel 6 Werden durch den Entwickler diese Grundregeln nicht beachtet, so kann dies dazu führen, dass das SAP-System im täglichen Gebrauch „lahm gelegt“ wird. In einem SAP-System werden zur Einbindung von SQL-Datenbanken keine Anweisungen in einem ABAP-Programm benutzt wie dies beispielsweise bei PHP der Fall ist. Die Datenbanken werden hier mit administrativen Rechten im Dirctionary eingebunden und dann im Programm wie externe Tabellen behandelt. Eine Anfrage erfolgt wie oben beschrieben mittels der SELECT–Anweisung. Jede SQL-Anweisung versorgt die beiden Systemfelder SY-SUBRC und SY-DBCNT mit Rückgabewerten. Dabei wird der Wert von SY-SUBRC auf Null gesetzt, wenn der Datenbankzugriff erfolgreich war. Das Systemfeld SY-DBCNT enthält nach einem Datenbankzugriff die Anzahl der bearbeiteten Tabellenzeilen. Aufgrund der Ähnlichkeit der Behandlung von externen Tabellen und SQL-Datenbanken wird an dieser Stelle nicht weiter auf OpenSQL eingegangen. Kapitel 1 Kapitel 2 Kapitel 3 Datenbearbeitung mit OpenSQL Kapitel 4 Kapitel 5 -2- Kapitel 6 Dynamische Programmierung In diesem Kapitel soll die Dynamik innerhalb von ABAP angesprochen werden. Es soll ab sofort möglich sein, interaktiv in den Programmablauf eingreifen zu können. Eine Möglichkeit von dreien sind die Selektionsbilder. Doch bevor näher darauf eingegangen werden kann, sind noch einige Worte zu den Dynpros im Allgemeinen zu verlieren, da diese den Überbau aller Dynamik in SAP bilden. Diese Lerneinheit wird sich also in zwei große Abschnitte aufteilen. Zum ersten die Dynpros und Allgemeines zum dynamischen Programmieren in ABAP und zum zweiten Selektionsbilder, eine erste Möglichkeit eigene Werte während der Laufzeit dem Programm zu übergeben. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -1- Dynamische Programmierung Kapitel 5 Kapitel 6 Allgemeines zur dynamischen Programmierung: Was ist ein Dynpro? Der Begriff dynpro wird aus den Worten "dynamisch“ und „Programm" abgeleitet. Innerhalb von ABAP wird alles, was in irgendeiner Weise dynamisch ist als Dynpro bezeichnet. Selektionsbilder sind also auch eine Art Dynpro. Allgemein besteht jedes Dynpro aus einem Bildschirmbild (oder mehreren) und aus einer Ablauflogik. Das Bildschirmbild kann auf zwei verschiedene Weisen erstellt werden. Zum einen mit dem ScreenPainter, einem Werkzeug, dass nur zum Erstellen von Ein- und Ausgabemasken konstruiert wurde und zum anderen mit dem ABAP Editor. Bei der letzteren Möglichkeit werden entsprechende Befehle genutzt, um ein Bildschirmbild zu erstellen. Die Ablauflogik ist wiederum in verschiedene Teile aufzuspalten. Die Wichtigsten sind PBO und PAI. Dabei ist PBO (Process Before Output) der Programmteil, der vor der Ausgabe des Bildschirmbildes verarbeitet wird. PAI (Process After Input) ist der Teil der Ablauflogik, der nach der Eingabe der Daten durch den Nutzer ausgeführt wird. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -2- Dynamische Programmierung Kapitel 5 Kapitel 6 Es gibt noch zwei weitere Teile in der Ablauflogik, die im Gegensatz zu den beiden eben genannten nicht unbedingt notwendig sind, POH (Process On Help Request) und POV (Process On Value Request). Der Erste Teil wird aktiviert, wenn der Nutzer die Hilfe aufruft und der POH wird ausgeführt, sobald der Nutzer in einem Eingabefeld die Taste F4 betätigt, also eine Eingabehilfe anfordert. Anmerken sollte man auch, dass Dynpros den ABAP-Programmen unterzuordnen sind, d.h. ein ABAP-Programm kann mehrere Dynpros oder Dynprofolgen enthalten. Das Dynpro wird entweder durch einen Befehl im Programmcode aufgerufen oder von außerhalb durch einen Transaktionscode aktiviert. Die nun folgende Abbildung soll den Zusammenhang zwischen Dynpros und den ABAP-Programmen verdeutlichen. Im oberen Teil der Abbildung ist ein GUI-Status zu sehen. Dieser ist wie das Dynpro eine eigenständige Komponente eines ABAP-Programmes, kann ebenfalls Benutzeraktionen speichern und zur weiteren Verarbeitung an das ABAP-Programm weitergeben. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -3- Dynamische Programmierung Kapitel 5 Kapitel 6 Damit sollten Ihnen die Grundlagen von dynamischen Programmen bekannt sein und es kann zu den Selektionsbildern übergegangen werden. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -4- Dynamische Programmierung Kapitel 5 Kapitel 6 Selektionsbilder definieren: Der Selection-Screen: Selektionsbilder sind eine spezielle Art von Dynpros, deren Aufgabe darin besteht, Eingaben des Nutzers aufzunehmen. Wie der Name schon sagt, dienen die Eingaben meist zur näheren Beschreibung oder Eingrenzung von Selektionskriterien beim Zugriff auf Datenbanken. Um Selektionsbilder zu definieren, nutzt man den Befehl SELECTION-SCREEN BEGIN OF SCREEN <nr> [TITLE <Titel>] [AS WINDOW]. Alles was danach kommt, wird in den Selektionsbildschirm übernommen. Abgeschlossen wird der Block mit SELECTION-SCREEN END OF SCREEN <nr>. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -5- Dynamische Programmierung Kapitel 5 Kapitel 6 Mit dem Zusatz TITLE kann dem Bildschirm ein Titel zugeordnet werden. <Titel> ist eine Variable, der nach INITIALIZATION ein Wert zugewiesen wird. INITIALIZATION ist ein Ereignisschlüsselwort. Dieses Ereignis wird aktiviert, kurz bevor ein Selektionsbild auf dem Bildschirm erscheinen soll. Es können also bestimmte Werte gesetzt werden, die dann auf dem Bildschirm erscheinen sollen. Selektionsbilder werden in diesem Fall im Editor erstellt, und nicht mit dem ScreenPainter. SELECTION-SCREEN BEGIN OF SCREEN 501 TITLE tita. * An diese Stelle kommen die Nutzerabfragen. SELECTION-SCREEN END OF SCREEN 501. CALL SCREEN 501. INITIALIZATION. tita = 'Titel des Blockes'. Es wird ein Bildschirm definiert. Dieser Bildschirm erhält die Nummer 501 und wird mittels 'CALL SCREEN 501' aufgerufen. Dadurch wird INITIALIZATION ausgelöst. Die Variable 'tita' bekommt ihren Wert zugewiesen und danach wird der Bildschirm ausgegeben. Noch sind die Selektionsbildschirme leer. Wie und womit sie gefüllt werden, soll in den nächsten Abschnitten erläutert werden. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -6- Dynamische Programmierung Kapitel 5 Kapitel 6 Einfache Selektionsbildschirme: Die einfachste Art und Weise einen Wert vom Nutzer einzulesen ist, ein einzelnes Feld zu deklarieren. Mit dem Schlüsselwort PARAMETERS wird genau das getan. PARAMETERS funktioniert genauso wie die DATA-Anweisung, mit dem Unterschied, dass für jede unter PARAMETERS definierte Variable ein Eingabefeld auf dem Bildschirm erscheint. Kommt die Anweisung nicht innerhalb des SELECTION-SCREEN-Blockes, so wird ein Standardselektionsbild erstellt und sofort eine Eingabe gefordert. CALL SCREEN ist nicht erforderlich. PARAMETERS: name(15) vorname(15) gebjahr herr frau katalog newslett gratisge Kapitel 1 Kapitel 2 TYPE c OBLIGATORY, TYPE c OBLIGATORY, TYPE i DEFAULT 1970 , RADIOBUTTON GROUP r1 DEFAULT 'X', RADIOBUTTON GROUP r1, AS CHECKBOX DEFAULT 'X', AS CHECKBOX DEFAULT 'X', AS CHECKBOX DEFAULT 'X'. Kapitel 3 Kapitel 4 -7- Dynamische Programmierung Kapitel 5 Kapitel 6 In diesem Beispiel sind fast alle Möglichkeiten enthalten, die der Befehl bietet. Die ersten beiden Felder haben die Länge 15 und sind Mussfelder (Schlüsselwort: OBLIGATORY). Im dritten Feld wird ein Standardwert gesetzt. Das geschieht mit dem Schlüsselwort DEFAULT. Die beiden folgenden Felder sind Auswahlknöpfe, d.h. es kann nur eine Option ausgewählt werden. Auch hier kann mit DEFAULT eine Voreinstellung getroffen werden. Die drei letzten Variablen sind als Ankreuzfelder deklariert. Es ist hier möglich alle Felder einer Gruppe auszuwählen. Die Ausgabe sieht wie folgt aus. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -8- Dynamische Programmierung Kapitel 5 Kapitel 6 Die unter PARAMETERS angegebenen Feldnamen sind ganz normale Variablen und können im Laufe des Programms ausgewertet werden. Felder dürfen eine Länge von 8 Zeichen nicht überschreiten. Das gilt auch für solche, die mit PARAMETERS definiert werden! Bei Auswahlknöpfen ist zu beachten, dass diese in Gruppen angelegt werden müssen, denn innerhalb einer Gruppe darf nur eine Option ausgewählt werden. Weiterhin ist wichtig, dass die Variablen von Ankreuzfeldern und Auswahlknöpfen nur zwei Zustände haben: - Ausgewählt: Variable hat den Wert 'X', nicht Ausgewählt: Variable hat den Wert ' ' (leer). Soll geprüft werden, ob die Eingabe dem vordefinierten Typ entspricht, so ist an die Definition des Feldes ein VALUE CHECK anzuhängen. Dies ist jedoch nur möglich, wenn der Feldtyp im ABAP-Dictionary steht (z. B.: eine Spalte einer SAP-Tabelle ist). Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 -9- Dynamische Programmierung Kapitel 5 Kapitel 6 Komplexere Selektionsbildschirme: Für umfangreichere Selektionen bieten sich interne Tabellen an. Die Eingaben des Nutzers werden in eine Tabelle geschrieben und können später innerhalb einer OpenSQL-Anweisung auf eine Datenbanktabelle genutzt werden. Syntax: SELECT-OPTIONS <Tabelle> FOR <x>. DATA: x LIKE marm-matnr, BEGIN OF y, mnr LIKE marm-matnr, einh LIKE marm-meinh, END OF y. *… Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 10 - Dynamische Programmierung Kapitel 5 Kapitel 6 *… SELECT-OPTIONS tab FOR x. DATA: zeile LIKE tab. WRITE: / 'Zuerst die Interne Tabelle:'. WRITE / tab-high. WRITE / tab-low. SKIP TO LINE 6. WRITE : / 'High ','Low ', 'Sign ','Option'. LOOP AT tab INTO zeile. WRITE: / zeile-high,'|', zeile-low,'|', zeile-sign,'|' , zeile-option. ENDLOOP. SKIP. WRITE: / '... und nun das Ergebnis der Selektion:'. SELECT matnr meinh INTO y FROM marm WHERE matnr IN tab. WRITE: / y-mnr, y-einh. ENDSELECT. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 11 - Dynamische Programmierung Kapitel 5 Kapitel 6 Die Tabelle 'tab' wird als "Behälter" für die Bedingungen genutzt, nach der die Datenbanktabelle "makt" selektiert werden soll. Vor der Selektion werden noch die Spalten der Selektionstabelle ausgegeben. Danach erfolgt die eigentliche Selektion mit den Bedingungen, die in der internen Tabelle stehen und die Ausgabe. Eingabebildschirm Ausgebebildschirm Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 12 - Dynamische Programmierung Kapitel 5 Kapitel 6 Die Selektionstabelle besteht aus vier Spalten. Zwei Spalten (high, low) beinhalten die obere und untere Grenze des zu selektierenden Wertebereiches. Eine Spalte (sign) beschreibt, ob die in high und low angegebenen Werte mit zur Ergebnismenge gehören sollen, oder nicht. Diese Spalte kann die Werte 'I' = Inklusive oder 'E' = Exklusive enthalten. Die letzte Spalte (option) gibt an wie die Werte in low und high zu interpretieren sind. Mögliche Inhalte sind 'BT' = Between, 'NB' = Not Between, wenn in beiden Spalten Werte stehen. Ist jedoch die Spalte high leer, so gibt es nur noch die gängigen Vergleichsoperatoren (EQ, NE, GT, LE,...). Je nach Komplexität der Eingabe kann die Tabelle auch mehrere Zeilen enthalten. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 13 - Dynamische Programmierung Kapitel 5 Kapitel 6 Formatieren von Selektionsbildern: Verschönern des Selektionsbildschirmes: Die bisherigen Selektionsbilder waren nicht besonders ansprechend, daher soll in diesem Abschnitt versucht werden, den Eingabebildschirm etwas angenehmer zu gestalten. Folgende Befehle sind möglich: - - - SELECTION-SCREEN SKIP [<n>].: Fügt Leerzeilen ein. Die Zahl <n> gibt dabei die Anzahl der Leerzeichen an. SELECTION-SCREEN ULINE [/<p>[(<l>)]].: Es wird eine waagerechte Linie gezogen. Mit <p> kann die Startposition angegeben werden, <l> steht für die Länge. SELECTION-SCREEN COMMENT [/]<p>(<l>) <Kommentar> [FOR FIELD <feld>].: Mit diesem Befehl kann ein Kommentar zu einem Feld angegeben werden. P und l wird wie bei ULINE verwendet. Der Kommentar ist eine Variable, die nicht mit DATA deklariert werden darf. Die Zuweisung eines Wertes erfolgt erst nach dem Schlüsselwort INITIALIZATION. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 14 - Dynamische Programmierung Kapitel 5 Kapitel 6 SELECTION-SCREEN COMMENT 2(20) test FOR FIELD feld. PARAMETERS: feld(10) TYPE c. SELECTION-SCREEN ULINE /1(44). INITIALIZATION. test = 'Kommentar...'. Die Ausgabe stellt sich nun folgendermaßen dar. Des Weiteren gibt es die Möglichkeit, Kommentare auf die gleiche Zeile zu setzen wie das Feld selbst. Dazu wird ein Block verwendet, der mit SELECTION-SCREEN BEGIN OF LINE. beginnt und mit SELECTION-SCREEN END OF LINE. endet. Alles, was sich zwischen diesem Anweisungen befindet kommt auf eine Zeile. Es können beispielsweise auch mehrere Felder auf eine Zeile gesetzt werden. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 15 - Dynamische Programmierung Kapitel 5 Kapitel 6 Der Feldname kann nun nicht mehr angezeigt werden. Deswegen ist ein Kommentar zu verwenden, da der Nutzer sonst keinen Hinweis darauf hat, was er eingeben soll! SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(30) texta. PARAMETERS: p1(2) TYPE c, p2(2) TYPE c, p3(2) TYPE c. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN ULINE /1(39). INITIALIZATION. texta = 'Datum eingeben (TT MM JJ)'. In diesem Beispiel werden mehrere Felder auf eine Zeile gesetzt. Da die Feldnamen nicht angezeigt werden, ist ein Kommentar wichtig. Ausgabebildschirm Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 16 - Dynamische Programmierung Kapitel 5 Kapitel 6 Zuletzt soll beschrieben werden, wie man bestimmte Felder in einem Block zusammenfasst. Ein solcher Block wird mit SELECTION-SCREEN BEGIN OF BLOCK. eingeleitet und mit SELECTIONSCREEN END OF BLOCK. abgeschlossen. Zusätzlich kann noch angegeben werden, ob ein Rahmen benötigt wird, oder nicht. SELECTION-SCREEN BEGIN OF BLOCK rad1 WITH FRAME TITLE tita. PARAMETERS name(20) TYPE c. PARAMETERS vorname(20) TYPE c. PARAMETERS strasse(20) TYPE c. SELECTION-SCREEN END OF BLOCK rad1. INITIALIZATION. tita = 'Titel des Blockes'. Ausgabebildschirm Blöcke dieser Art können bis zu einer Tiefe von fünf geschachtelt werden. Damit sollte es Ihnen möglich sein, ihre Abfragen etwas ansprechender zu gestalten. Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 17 - Dynamische Programmierung Kapitel 5 Kapitel 6 Aufgaben: 1. Schreiben Sie ein Programm, dass Ihren Namen, Vornamen und ihr Alter entgegennehmen kann. Lassen Sie sich die Daten anschließend wieder ausgeben. 2. Schreiben Sie ein Programm, dass sie mittels Ankreuzfeldern und Checkboxen fragt, ob sie ein kleines, mittleres oder großes Eis wollen, und welche Geschmacksrichtungen enthalten sein sollen. 3. Erweitern Sie Ihr "Eisprogramm" so, dass der Selektionsbildschirm schöner aussieht. Nutzen Sie Rahmen und Kommentare. 4. Erstellen Sie einen Selektionsbildschirm, der ihre Selektionskriterien zur Spalte 'matnr' der Tabelle 'marm' entgegennimmt, diese Daten in eine interne Tabelle schreibt, die Selektion ausführt und das Ergebnis ausgibt (Spalte 'matnr' und Spalte 'meinh'). Kapitel 1 Kapitel 2 Kapitel 3 Kapitel 4 - 18 - Dynamische Programmierung Kapitel 5 Kapitel 6