To open a cursor for a SELECT statement, use the following:
OPEN CURSOR [WITH HOLD] <c> FOR SELECT <result>
FROM <source>
[WHERE <condition>]
[GROUP BY <fields>]
[HAVING <cond>]
[ORDER BY <fields>].
You must first have declared the cursor <c> using the DATA statement and the special data type CURSOR. You can use all clauses of the SELECT statement apart from the INTO clause.
Furthermore, you can only formulate the SELECT clause [Page 1087] so that the selection consists of more than one line. This means that you may not use the SINGLE addition, and that the column selection may not contain only aggregate expressions.
An open cursor points to an internal handler, similarly to a reference variable pointing to an object. You can reassign cursors so that more than one points to the same handler. In a MOVE statement, the target cursor adopts all of the attributes of the source cursor, namely its position, and all of the clauses in the OPEN CURSOR statement.
You can also open more than one cursor in parallel for a single database table. If a cursor is already open, you cannot reopen it. To close a cursor explicitly, use the following statement:
CLOSE CURSOR <c>.
You should use this statement to close all cursors that you no longer require, since only a limited number of cursors may be open simultaneously. With one exception, a database LUW [Page 1314] is concluded when you close a cursor either explicitly or implicitly. The WITH HOLD addition in the OPEN CURSOR statement allows you to prevent a cursor from being closed when a database commit occurs in Native SQL [Page 1161].
Reading Data
An open cursor is linked to a multiple-line selection in the database table. To read the data into a target area in the ABAP program, use the following:
FETCH NEXT CURSOR <c> INTO <target>.
This writes one line of the selection into the target area <target>, and the cursor moves one line further in the selection set. The fetch statement decouples the INTO clause [Page 1094] from the other clauses in the SELECT statement. The target area <target> must be a flat-structured variable, since only single lines can be passed. Otherwise, the rules for the INTO clause are the same as in the SELECT statement.
If the cursor is on a list line, the system sets SY-SUBRC to 0, otherwise to 4. After a FETCH statement, the system field SY-DBCNT contains the number of lines already read by the current cursor.
Examples
DATA: C1 TYPE CURSOR, C2 TYPE CURSOR.
DATA: WA1 TYPE SPFLI, WA2 TYPE SPFLI.
DATA: FLAG1, FLAG2.
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.
The output is as follows:
Using a Cursor to Read Data
The database table SPFLI is read using two cursors, each with different conditions.
The selected lines are read alternately in a DO loop.
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.
The following is an extract from the list display:
The program opens a cursor for the database table SBOOK. After the first FETCH statement, a subroutine is called, which is dependent on the contents of the
SMOKER column. The cursor is passed to an interface parameter in the subroutine.
The subroutines read further lines until the contents of the SMOKER column change.
The subroutines perform different tasks using the lines read by the cursor.
DATA: WA_SPFLI TYPE SPFLI, WA_SFLIGHT TYPE SFLIGHT.
DATA: C1 TYPE CURSOR, C2 TYPE CURSOR.
Using a Cursor to Read Data
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.
FETCH NEXT CURSOR C2 INTO WA_SFLIGHT.
IF SY-SUBRC <> 0 OR WA_SFLIGHT-CARRID <> WA_SPFLI-CARRID OR WA_SFLIGHT-CONNID <> WA_SPFLI-CONNID.
EXIT.
ELSE.
WRITE: / WA_SFLIGHT-CARRID, WA_SFLIGHT-CONNID, WA_SFLIGHT-FLDATE.
ENDIF.
ENDDO.
ENDDO.
The output is as follows:
The program opens a cursor for each of the table SPFLI and SFLIGHT. Since both tables are linked by a foreign key relationship, it is possible to program a nested loop by sorting the selection by its primary key, so that the data read in the inner loop depends on the data in the outer loop. This programming method is quicker than
using nested SELECT statements, since the cursor for the inner loop does not continually have to be reopened.