In a previous post I wrote about how to perform an update of the current row/record when using a SQL cursor in a RPG program. I have been asked what could be considered the obvious follow on question: How I delete the current row/record when using a SQL cursor?
Fortunately it is as simple as the Update process. All I need to do is...
- Define the cursor
- Open the cursor
- Fetch from the cursor
- Delete
- Close the cursor
In its simplest form a program could just be like this:
01 **free
02 dcl-ds Record extname('TESTFILE') ;
03 end-ds ;
04 exec sql DECLARE C0 CURSOR FOR
SELECT * FROM TESTFILE
WITH NC ;
05 exec sql OPEN C0 ;
06 exec sql FETCH NEXT FROM C0 INTO :Record ;
07 exec sql DELETE TESTFILE WHERE CURRENT OF C0 ;
08 exec sql CLOSE C0 ;
09 *inlr = *on ;
|
This program will delete the first row/record it fetches.
Line 1: I want my RPG code to be free!.
Line 2 and 3: I will be fetching the row of data into this data structure. I have used the EXTNAME keyword to use the file's definition to define the data structure.
Line 4: My cursor is defined to select all the rows/fields from the table/file, and with no commitment control.
Line 5: I open the cursor.
line 6: I fetch the next, first, row from the cursor and move the fetched data to the data structure defined.
Line 7: This delete uses the WHERE CURRENT OF followed by the cursor's name. Therefore, the current row/record retrieved is deleted.
Line 8: At the end I close the cursor.
Yes, it is as simple as that. Having compiled this program when I run it, and as I would expect the first record is deleted.
Now let me make this more complicated. In the next example I want to update certain cursor rows/records and delete others. My example program looks like:
01 **free
02 ctl-opt option(*nodebugio:*srcstmt:*nounref) ;
03 dcl-ds Record extname('TESTFILE') qualified ;
04 end-ds ;
05 exec sql DECLARE C0 CURSOR FOR
SELECT * FROM TESTFILE
FOR UPDATE OF PSTAMP
WITH NC ;
06 exec sql OPEN C0 ;
07 dow (1 = 1) ;
08 exec sql FETCH NEXT FROM C0 INTO :Record ;
09 if (SQLCOD <> 0) ;
10 leave ;
11 endif ;
12 if (Record.RECSTS = 'U') ;
13 exec sql UPDATE TESTFILE
SET PSTAMP = CURRENT_TIMESTAMP
WHERE CURRENT OF C0 ;
14 elseif (Record.RECSTS = 'D') ;
15 exec sql DELETE TESTFILE
WHERE CURRENT OF C0 ;
16 endif ;
17 enddo ;
18 exec sql CLOSE C0 ;
19 *inlr = *on ;
|
How does this differ from my first example.
Line 2: I have defined my favorite control options.
Line 3: I have used the QUALFIED keyword in the data structure definition, therefore, I must prefix the data structures subfields with the data structure name.
Line 5: The cursor is defined almost the same as it was for the update of the current cursor. The only difference is that I only want to update one column/field, PSTAMP, in the cursor.
Lines 7 – 17: I am going to fetch all the rows/records from the cursor, therefore, I am using a Do loop.
Line 8: Here is the fetch of the cursor's data to the data structure.
Line 9 – 11: If the returned SQL code is not zero then an error occurred, which is more than likely the "end of file".
Line 12: If the Record Status subfield in the data structure is "U"...
Line 13: ... Then I want to update the current row/record column/field PSTAMP with the current timestamp.
Line 14: If (I prefer IF-ELSEIF to SELECT) the Record Status is "D"...
Line 15: ... Then I want to delete the current row/record.
Line 18: After all the rows/records have been fetched I want to close the cursor.
When I run this program it does exactly what I want, see below. All the rows/records with a Record Status of "D" were deleted, and those with "U" contain timestamp of when the row/record was updated.
BEFORE KEYFLD RECSTS PSTAMP 1 U 0001-01-01-00.00.00.000000 2 D 0001-01-01-00.00.00.000000 3 U 0001-01-01-00.00.00.000000 4 D 0001-01-01-00.00.00.000000 5 U 0001-01-01-00.00.00.000000 6 D 0001-01-01-00.00.00.000000 AFTER KEYFLD RECSTS PSTAMP 1 U 2018-05-16-02.09.15.936215 3 U 2018-05-16-02.09.15.940090 5 U 2018-05-16-02.09.15.940173 |
This article was written for IBM i 7.3, and should work for earlier releases too.



I normally use a (SELECT+WHEN) like
ReplyDeleteSELECT ;
when (Record.RECSTS = 'U') ;
exec sql UPDATE TESTFILE
SET PSTAMP = CURRENT_TIMESTAMP
WHERE CURRENT OF C0 ;
when (Record.RECSTS = 'D') ;
exec sql DELETE TESTFILE
WHERE CURRENT OF C0 ;
ENDSL ;