Anfang des InhaltsbereichsDaten über Cursor lesen Dokument im Navigationsbaum lokalisieren

Bei der normalen SELECT-Anweisung werden die Daten der Selektion immer direkt während der Ausführung der SELECT-Anweisung in den Zielbereich der INTO-Klausel geschrieben. Beim Lesen über Cursor kann die Übergabe der Daten von der Datenbank an das ABAP-Programm von der SELECT-Anweisung entkoppelt werden. Hierfür muß ein Cursor für eine SELECT-Anweisung geöffnet werden. Danach können die Zeilen der Selektion einzeln in einen flachen Zielbereich gestellt werden.

Cursor öffnen und schließen

Um einen Cursor für eine SELECT-Anweisung zu öffnen, schreibt man:

OPEN CURSOR [WITH HOLD] <c> FOR SELECT      <result>
                                  FROM      <source>
                                  [WHERE    <condition>]
                                  [GROUP BY <fields>]
                                  [HAVING   <cond>]
                                  [ORDER BY <fields>].

Der Cursor <c> muß vorher mit einer DATA-Anweisung und dem speziellen Datentyp CURSOR deklariert werden. Es können alle Klauseln der SELECT-Anweisung verwendet werden bis auf die INTO-Klausel. Weiterhin können in der SELECT-Klausel nur solche Angaben gemacht werden, bei denen die Selektion aus mehreren Zeilen und nicht aus einer einzelnen Zeile besteht. Das bedeutet es darf nicht der Ausdruck SINGLE für <lines> verwendet werden und die Spaltenauswahl <cols> darf nicht nur Aggregatausdrücke enthalten.

Ein geöffneter Cursor zeigt auf einen systeminternen Behandler, ähnlich wie eine Referenzvariable auf ein Objekt zeigt. Mehrere Cursor können durch Zuweisungen auf den gleichen Behandler zeigen. Bei einer MOVE-Zuweisung übernimmt der Zielcursor alle Eigenschaften des Quellcursors, also den Cursorstand und alle Klauseln der Anweisung Open Cursor.

Es können mehrere Cursor parallel für eine Datenbanktabelle geöffnet werden. Ein bereits geöffneter Cursor <c> kann nicht erneut geöffnet werden. Um einen geöffneten Cursor explizit zu schließen, verwendet man:

CLOSE CURSOR <c>.

Alle Cursor, die nicht länger benötigt werden sollten so geschlossen werden, da nur eine beschränkte Anzahl Cursor gleichzeitig geöffnet sein kann. Weiterhin werden mit einer Ausnahme alle geöffneten Cursor beim expliziten oder impliziten Abschluß einer Datenbank-LUW geschlossen. Mit dem Zusatz WITH HOLD in der Anweisung OPEN CURSOR kann das schließen eines Cursors beim Aufruf eines Datenbank-Commits in Native SQL verhindert werden.

Daten lesen

Ein geöffneter Cursor ist mit einer mehrzeiligen Selektion auf der Datenbanktabelle verknüpft. Um die Daten in einen Zielbereich im ABAP-Programm zu lesen, verwendet man:

FETCH NEXT CURSOR <c> INTO <target>.

Es wird eine Zeile der Selektion in den Zielbereich <target> geschrieben und der Cursor bewegt sich auf der Selektion eine Zeile weiter. Die Fetch-Anweisung entkoppelt die INTO-Klausel von den übrigen Klauseln der SELECT-Anweisung. Es können alle INTO-Klauseln der SELECT-Anweisung verwendet werden. Die Anweisung liest die Zeilen, die benötigt werden, um den Zielbereich der INTO-Klausel zu füllen und bewegt den Cursor auf die nächste zu lesende Zeile.

Solange noch nicht alle Zeilen der Selektion gelesen worden sind, wird SY-SUBRC auf 0 gesetzt, ansonsten auf 4. Das Systemfeld SY-DBCNT enthält nach einer FETCH-Anweisung die Anzahl aller bisher für den entsprechenden Cursor gelesenen Zeilen.

Beispiel

REPORT demo_select_cursor_1.

DATA: c1 TYPE cursor,
      c2 TYPE cursor.

DATA: wa1 TYPE spfli,
      wa2 TYPE spfli.

DATA: flag1(1) TYPE c,
      flag2(1) TYPE c.

OPEN CURSOR: c1 FOR SELECT  carrid connid
                      FROM  spfli
                      WHERE carrid = 'LH',

             c2 FOR SELECT  carrid connid cityfrom cityto
                      FROM  spfli
                      WHERE carrid = 'AZ'.

DO.
  IF flag1 NE 'X'.
    FETCH NEXT CURSOR c1 INTO CORRESPONDING FIELDS OF wa1.
    IF sy-subrc <> 0.
      CLOSE CURSOR c1.
      flag1 = 'X'.
    ELSE.
      WRITE: / wa1-carrid, wa1-connid.
    ENDIF.
  ENDIF.
  IF flag2 NE 'X'.
    FETCH NEXT CURSOR c2 INTO CORRESPONDING FIELDS OF wa2.
    IF sy-subrc <> 0.
      CLOSE CURSOR c2.
      flag2 = 'X'.
    ELSE.
      WRITE: / wa2-carrid, wa2-connid,
               wa2-cityfrom, wa2-cityto.
    ENDIF.
  ENDIF.
  IF flag1 = 'X' AND flag2 = 'X'.
    EXIT.
  ENDIF.
ENDDO.

Die Listenausgabe ist in etwa:

Diese Grafik wird im zugehörigen Text erklärt

Die Datenbanktabelle SPFLI wird über zwei Cursor unter verschiedenen Bedingungen gelesen. Die selektierten Zeilen werden abwechselnd innerhalb einer DO-Schleife eingelesen.

Beispiel

REPORT demo_select_cursor_2.

DATA c TYPE cursor.

DATA wa TYPE sbook.

OPEN CURSOR c FOR SELECT     carrid connid fldate bookid smoker
                    FROM     sbook
                    ORDER BY carrid connid fldate smoker bookid.

FETCH NEXT CURSOR c INTO CORRESPONDING FIELDS OF wa.

WHILE sy-subrc = 0.
  IF wa-smoker = ' '.
    PERFORM nonsmoker USING c.
  ELSEIF wa-smoker = 'X'.
    PERFORM smoker USING c.
    SKIP.
  ELSE.
    EXIT.
  ENDIF.
ENDWHILE.

FORM nonsmoker USING n_cur TYPE cursor.
  WHILE wa-smoker = ' ' AND sy-subrc = 0.
    FORMAT COLOR = 5.
    WRITE: / wa-carrid, wa-connid, wa-fldate, wa-bookid.
    FETCH NEXT CURSOR n_cur INTO CORRESPONDING FIELDS OF wa.
  ENDWHILE.
ENDFORM.

FORM smoker USING s_cur TYPE cursor.
  WHILE wa-smoker = 'X' AND sy-subrc = 0.
    FORMAT COLOR = 6.
    WRITE: / wa-carrid, wa-connid, wa-fldate, wa-bookid.
    FETCH NEXT CURSOR s_cur INTO CORRESPONDING FIELDS OF wa.
  ENDWHILE.
ENDFORM.

Ein Ausschnitt der Listenausgabe ist etwa:

Diese Grafik wird im zugehörigen Text erklärt

Es wird ein Cursor für die Tabelle SBOOK geöffnet. Nach der ersten FETCH-Anweisung wird je nach Inhalt der Spalte SMOKER ein Unterprogramm aufgerufen. Der Cursor wird an einen Schnittstellenparameter der Unterprogramme übergeben. Die Unterprogramme lesen weitere Zeilen, bis sich der Inhalt der Spalte SMOKER ändert. In den Unterprogrammen sind unterschiedliche Aktionen für die gelesenen Zeilen programmiert.

Beispiel

REPORT demo_select_cursor_3.

DATA: wa_spfli   TYPE spfli,
      wa_sflight TYPE sflight,
      wa_sflight_back TYPE sflight.

DATA: c1 TYPE cursor,
      c2 TYPE cursor.

OPEN CURSOR c1 FOR     SELECT *
                 FROM  spfli
                 ORDER BY PRIMARY KEY.

OPEN CURSOR c2 FOR     SELECT *
                 FROM  sflight
                 ORDER BY PRIMARY KEY.

DO.
  FETCH NEXT CURSOR c1 INTO wa_spfli.
  IF sy-subrc NE 0.
    EXIT.
  ENDIF.
  WRITE: / wa_spfli-carrid, wa_spfli-connid.
  DO.
    IF NOT wa_sflight_back IS INITIAL.
      wa_sflight = wa_sflight_back.
      CLEAR wa_sflight_back.
    ELSE.
      FETCH NEXT CURSOR c2 INTO wa_sflight.
      IF  sy-subrc <> 0.
        EXIT.
      ELSEIF wa_sflight-carrid <> wa_spfli-carrid
          OR wa_sflight-connid <> wa_spfli-connid.
        wa_sflight_back = wa_sflight.
        EXIT.
      ENDIF.
    ENDIF.
    WRITE: / wa_sflight-carrid, wa_sflight-connid,
             wa_sflight-fldate.
  ENDDO.
ENDDO.

Die Listenausgabe ist etwa:

Diese Grafik wird im zugehörigen Text erklärt

Es werden zwei Cursor für die Tabellen SPFLI und SFLIGHT geöffnet. Da beide Tabellen über eine Fremschlüsselbeziehung miteinander verknüpft sind, kann durch die Sortierung der Selektion nach dem Primärschlüssel eine geschachtelte Schleife über die Tabellen programmiert werden, wobei die Daten der inneren Schleife in Abhängigkeit von den Daten der äußeren Schleife gelesen werden. Diese Programmierung ist performanter als mit geschachtelten SELECT-Schleifen, da der Cursor für die innere Schleife nicht immer wieder neu aufgesetzt werden muß. Bei einem Gruppenstufenwechsel in der inneren Schleife werden die gelesenen Daten bis zum nächsten Schleifendurchlauf zwischengespeichert, da ein Zurücksetzen des Cursors nicht möglich ist.

 

 

Ende des Inhaltsbereichs