Embedding SQL in RPG

advertisement
Embedding SQL in RPG
Why SQL?
•
•
•
SQL is the IBM standard for relational database access
SQL is the industry standard for relational database access
SQL is the defacto standard for Client/Server data retrieval
– Don’t ask me what that means – it was in an IBM-supplied slide
SQL Terms
System Name
Related SQL Term
Library
Physical File
Record
Field
Schema
Table
Row
Column
SQL Commands
•
SELECT
– Retrieves data from a file (or table in SQL terms)
•
UPDATE
– Updates a record (row) in a file (table)
•
DELETE
– Deletes a record (row) from a file (table)
•
INSERT
– Adds a record (row) to a file (table)
Full disclosure: I have not used the UPDATE, DELETE, or INSERT commands
in an RPG program yet. (Perhaps Tony has and can share some info with
us.)
Additional SQL Functions
•
DECLARE (CURSOR)
– Sets the “rules” for what data will be included in the temporary result table and
how to sequence it
– Similar to the FILE, QRYSLT and KEYFLD keywords on an OPNQRYF in a CL
program
•
OPEN and CLOSE (CURSOR)
– Opens and closes the temporary result table
– Similar to the OVRDBF, OPNQRYF, and CLOF statements in a CL program
•
FETCH
– Retrieves data from the temporary result table
– Similar to the READ or READP Op-Codes in RPG
•
COMMIT/ROLLBACK (journaling functions) and GRANT/REVOKE (security
functions) will not be addressed in this session (primarily because I have not
used them to this point).
RPG Source Types
• SQLRPGLE
• SQLRPG
•
•
•
This option (embedded SQL) is not automatically included in the iSeries OS
It is a billable add-on
If your system does not allow it, you can create the source, but you can’t compile them. You can
run the compiled objects if they are compiled on a system that does allow it.
•
These source types go through a “pre-compiler” that parses (interprets) the SQL statements
before compiling the RPG code.
Compiler Directives
•
SQL Commands are embedded between 2 compiler directives
–
–
–
–
–
C/EXEC SQL
C+ Place your
C+ SQL command
C+ here
C/END-EXEC
The DECLARE Function
d
d empnbr
d empnam
d empdpt
ds
1
6
31
5 0
30
33 0
c/exec sql
c+ DECLARE emp_cursor CURSOR for SELECT nbr, nam, dpt INTO :empnbr,
c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BY
c+ dpt, nam
c/end-exec
•
•
•
•
Program variables must be preceded by a colon
The INTO clause identifies where the data from the retrieved fields (columns) will be stored
– Can be specified here or on the FETCH statement
The WHERE clause identifies records to be retrieved (QRYSLT)
The ORDER BY clause identifies sorting criteria (KEYFLD).
–
ORDER BY dpt DESCEND
Additional DECLARE Options
•
FOR UPDATE OF (Field Name)
– Default is ALL columns (fields) can be updated and ALL rows (records) can be deleted
– FOR UPDATE OF lists the columns that are to be updated
• Columns listed in the ORDER BY clause may not be listed in the FOR UPDATE OF
clause
•
FOR READ ONLY
– Specifies no updating/deleting allowed
– May improve performance
•
WITH HOLD
– Default: Cursors close when Commit/Rollback commands execute
– WITH HOLD keeps the cursor open
The OPEN Function
c/exec sql
c+ OPEN emp_cursor
c/end-exec
The FETCH Function
c/exec sql
c+ FETCH NEXT FROM emp_cursor
c/end-exec
As mentioned earlier, the INTO clause can also be used here
c/exec sql
c+ FETCH NEXT FROM emp_cursor INTO :empnbr, :empnam,
:empdpt
c/end-exec
• Make sure your fields on the SELECT match your fields on the INTO
Additional FETCH Options
Alternatives to NEXT
•
•
•
•
•
•
•
PRIOR
FIRST
LAST
BEFORE
AFTER
CURRENT
RELATIVE n
Retrieves the row before the current row
Retrieves the first row
Retrieves the last row
Positions the cursor before the first row (do NOT use INTO)
Positions the cursor after the last row (do NOT use INTO)
Retrieves the current row (no change in cursor position)
If n < -1 Retrieves the nth row before the current row
If n = -1 Same as PRIOR
If n = 0 Same as CURRENT
If n = 1 Same as NEXT
If n > 1 Retrieves the nth row after the current row
DECLARE for FETCH PRIOR
c/exec sql
c+ DECLARE emp_cursor SCROLL CURSOR for SELECT nbr, nam, dpt INTO
:empnbr,
c+ :empnam, :empdpt FROM empmas WHERE mar_stat = ‘M’ ORDER BY
c+ dpt, nam
c/end-exec
SCROLL makes it possible for you to read forward or backward.
Example of RELATIVE
c/exec sql
c+ FETCH RELATIVE 5000 FROM emp_cursor
c/end-exec
Same as…
c
do
5000
c/exec sql
c+ FETCH NEXT FROM emp_cursor
c/end-exec
c
enddo
FETCH and data structures
D emp_ds
D
D
D
ds
1 5 0 nbr
6 30
name
31 31
job
c/exec sql
C+ declare emp_cursor cursor for select emp_nbr, emp_name, emp_job
C+ from emp
c/end-exec
c/exec sql
C+ FETCH NEXT FROM emp_cursor INTO :empds
c/end-exec
Full disclosure: I haven’t tried this either. IBM’s slide says it should work.
UPDATE
•
As I said earlier, I haven’t used this command in an RPG program myself
yet, but I found an example:
c/exec sql
c+ update emp
c+ set sal = sal + :raise
c+ where current of empcsr
c/end-exec
Will update the currently read record, by adding a program field called raise to
the file field called sal
The CLOSE Function
c/exec sql
c+ CLOSE emp_cursor
c/end-exec
Error Detection & Handling
The field SQLCODE stores a return code after every SQL command is
executed:
• = 0 Successful statement execution
• > 0 Successful statement execution, with warning condition
• < 0 Unsuccessful statement execution
The value indicates the exact condition:
• 100 = Row not found
• -522 = Not authorized to object
Error Detection (Cont’d)
WHENEVER statement checks the SQLCA (SQL Communications Area) and
can branch to a location based on a condition. There are 3 conditions:
• SQLWARNING (SQLCODE > 0 but not = 100)
• SQLERROR (SQLCODE < 0)
• NOT FOUND (SQLCODE = 100)
And 2 possible actions:
• CONTINUE
• GO TO
•
•
•
•
c/exec sql
c+ FETCH NEXT FROM emp_cursor INTO :empds where emp_nbr = 500
c+ WHENEVER NOT FOUND GO TO not_found_tag
c/end-exec
Error Detection (Cont’d)
Check for an error after every command:
c/exec sql
c+ FETCH NEXT FROM emp_cursor INTO :empds where emp_nbr = 500
c/end-exec
C
C
C
if
exsr
endif
sqlcode <> 0
sr_err
Dynamic SQL
What is Dynamic SQL?
• SQL statements are not predefined in program
– Dynamically created on the fly as part of program logic
•
PREPARE statement can be used in program logic to compile dynamically
created SQL statements
•
Used when run time variables are involved in the selection process or the
exact syntax of an SQL statement cannot be pre-determined for any other
reason
•
Since dynamic SQL statements did not go through the precompiler, they
need to be interpreted and executed within the program – this can make
them resource intensive.
400
500
600
700
800
900
1000
1100
1200
1300
1400
1500
1600
1700
1800
1900
2000
2100
2200
2300
2400
2500
2600
2700
2800
2900
3000
3100
3200
3300
3400
3600
3600
3700
3800
3900
4000
4100
4200
4300
4400
4500
4600
4700
4800
4900
6000
5100
5200
d SQL_ok c coost)0)
d SQL_more s n
inz(*on)
d SQL stmt s 500
inz)’select esbnr, eeleb, aspack,
d esupc, essc, asmcd, esbri, aslaei,
d asbez, es esdnr from artmep
d where’)
* Declare SQL Cursor
c/exec sql
c+ declare artmap cursor scroll cursor for sl
c/eod-exec
SQL stmt %trimr(SQLstmt) + ‘ ‘ +
‘‘‘ + scfleg +
curr group = 1
c
c
c
eval
‘ASFL =
eval
c
c
c
c
c
c
c
c
select
when
scselt = ‘P
evel
SQL stmt = %trimr(SQLstmt) + ‘ end ‘ +
‘ASEG between 700 and 799’
when
scselt = ‘B’
eval
SQL stmt
%trimr(SQLstmt) + end ‘ +
‘ASEG not between 700 and 799’
endsl
c
c
c
c
if
scquel <> *blenks
eval
SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +
‘ASMCD = ‘ ‘ ‘ + scqual + ‘ ‘
endif
c
c
c
c
if
scwid c> 0
eval
SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +
‘ASBNI = ‘ + scwidalph
endif
c
c
c
c
if
eden <> 0
eval
SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ +
‘ASLAEI ‘ + sclenalph
endif
c
c
c
c
if
sclicn c> 0
eval
SQL stmt = %trimr(SQLstmt) + ‘ and ‘ +
‘ASLIZD = ‘ + sclicnalph
endif
c
c
c
c
if
scstyl c>
eval
SQL stmt = %trimr(SQLstmt) ÷ ‘ and ‘ +
‘ASSNR = ‘ ‘ ‘ + scstyl ÷ ‘ ‘ ‘
endif
7700
7800
7900
8000
*Prepare variable SQL statement
c/exec sql
c+
prepare s1 from :SQL_stmt
c/end-exec
The DECLARE statement declared a cursor called ARTMAP, so you would
perform your FETCH from ARTMAP just as if this had been a pre-defined
select statement instead of a prepared one.
Download