Professional Documents
Culture Documents
Paul Tuohy Embedded SQL in RPG - Beyond The Basics
Paul Tuohy Embedded SQL in RPG - Beyond The Basics
Agenda ComCon
Keys to Embedded SQL
Writing SQL to Embed
Tools
Methodology
Controlling CRTSQLRPGI
SQLCA and SQLCODE considerations
Getting data without SELECT
GET DIAGNOSTICS
VALUES INTO
Mastering Multi Row Fetch
Page at a time processing
Handling NULL
Dates, Times and Timestamps
Visual
Visual Explain
Explain
Visual Explain
Ready
Ready for
for copy/paste
copy/paste to to RSE,
RSE,
Leading
Leading Spaces
Spaces but
but first...
first...
Guess What?
/free
/free
exec SQL
exec SQL
set option commit = *NONE,
set option commit = *NONE,
naming = *SYS,
naming = *SYS,
datFmt = *ISO,
datFmt = *ISO,
datSep = '-',
datSep = '-',
srtSeq = *LANGIDSHR;
srtSeq = *LANGIDSHR;
/end-Free
/end-Free
exec SQL
exec SQL
declare C1 scroll cursor for
declare C1 scroll cursor for
select deptNo, deptName from department order by deptNo
select deptNo, deptName from department order by deptNo
for read only;
for read only;
exec SQL
exec SQL
open C1;
open C1;
exec SQL
exec SQL
get diagnostics :numRows1 = DB2_NUMBER_ROWS;
get diagnostics :numRows1 = DB2_NUMBER_ROWS;
dsply ('Open C1 DB2_NUMBER_ROWS= ' + %char(numRows1));
dsply ('Open C1 DB2_NUMBER_ROWS= ' + %char(numRows1));
Open C1 DB2_NUMBER_ROWS= 14
Open C1 DB2_NUMBER_ROWS= 14
exec SQL
exec SQL
open C1;
open C1;
exec SQL
exec SQL
get diagnostics :numRows1 = DB2_NUMBER_ROWS;
get diagnostics :numRows1 = DB2_NUMBER_ROWS;
dsply ('Open C1 DB2_NUMBER_ROWS= ' + %char(numRows1));
dsply ('Open C1 DB2_NUMBER_ROWS= ' + %char(numRows1));
exec SQL
exec SQL
fetch first from C1 for :getRows rows into :data ;
fetch first from C1 for :getRows rows into :data ;
numRows2 = SQLERRD(3);
numRows2 = SQLERRD(3);
exec SQL
exec SQL
get diagnostics :numRows3 = DB2_NUMBER_ROWS;
get diagnostics :numRows3 = DB2_NUMBER_ROWS;
dsply ('Fetch SQLERRD(3)= ' + %char(numRows2));
dsply ('Fetch SQLERRD(3)= ' + %char(numRows2));
dsply ('Fetch DB2_NUMBER_ROWS= ' + %char(numRows3));
dsply ('Fetch DB2_NUMBER_ROWS= ' + %char(numRows3));
dsply ('SQLERRD(3) after Get Diagnostic= ' + %char(SQLERRD(3)));
dsply ('SQLERRD(3) after Get Diagnostic= ' + %char(SQLERRD(3)));
d system s 10a
d system s 10a
d myName s 5a inz('Paul')
d myName s 5a inz('Paul')
d aDate s d datFmt(*ISO) inz(D'2010-12-07')
d aDate s d datFmt(*ISO) inz(D'2010-12-07')
d dayNumber s 10i 0
d dayNumber s 10i 0
/free
/free
exec SQL values current server into :system ;
exec SQL values current server into :system ;
dsply ('System name is ' + system);
dsply ('System name is ' + system);
exec SQL values upper(:myName) into :myName;
exec SQL values upper(:myName) into :myName;
dsply ('My name in upper case is ' + myName);
dsply ('My name in upper case is ' + myName);
exec SQL values dayOfWeek(:aDate) into :dayNumber ;
exec SQL values dayOfWeek(:aDate) into :dayNumber ;
dsply ('Day of week is ' + %char(dayNumber));
dsply ('Day of week is ' + %char(dayNumber));
exec SQL values dayOfWeek_ISO(:aDate) into :dayNumber ;
exec SQL values dayOfWeek_ISO(:aDate) into :dayNumber ;
dsply ('ISO Day of week is ' + %char(dayNumber));
dsply ('ISO Day of week is ' + %char(dayNumber));
exec SQL values dayOfYear(:aDate) into :dayNumber ;
exec SQL values dayOfYear(:aDate) into :dayNumber ;
dsply ('Day of year is ' + %char(dayNumber));
dsply ('Day of year is ' + %char(dayNumber));
d copyEvent PI
d copyEvent PI
d fromEvent 5a const
d fromEvent 5a const
d toEvent 5a const
d toEvent 5a const
/free
/free
exec SQL declare global temporary table for_agenda as
exec SQL declare global temporary table for_agenda as
(select * from agenda where event = :fromEvent) with data;
(select * from agenda where event = :fromEvent) with data;
exec SQL update for_agenda
exec SQL update for_agenda
set event = :newEvent, change_number = 0;
set event = :newEvent, change_number = 0;
exec SQL insert into agenda (select * from for_agenda);
exec SQL insert into agenda (select * from for_agenda);
exec SQL commit;
exec SQL commit;
H option(*srcStmt : *noDebugIO))
H option(*srcStmt : *noDebugIO))
d data Ds qualified
d data Ds qualified
d deptNo 3a
d deptNo 3a
d deptName 36a varying
d deptName 36a varying
/include STANDARD
/include STANDARD
/free
/free
exec SQL
exec SQL
declare C1 cursor for
declare C1 cursor for
select deptNo, deptName from department order by deptNo
select deptNo, deptName from department order by deptNo
for read only;
for read only;
exec SQL
exec SQL
open C1;
open C1;
exec SQL
exec SQL
fetch next from C1 into :data ;
fetch next from C1 into :data ;
doW (SQLCODE >= 0 and SQLCODE <> 100);
doW (SQLCODE >= 0 and SQLCODE <> 100);
dsply ('Fetch Loop ' + data.deptNo + ' ' + data.deptName);
dsply ('Fetch Loop ' + data.deptNo + ' ' + data.deptName);
exec SQL
exec SQL
fetch next from C1 into :data ;
fetch next from C1 into :data ;
endDo;
endDo;
exec SQL
exec SQL
close C1;
close C1;
*inLR = *on;
*inLR = *on;
H option(*srcStmt : *noDebugIO)
H option(*srcStmt : *noDebugIO)
d MAX_ROWS C 10
d MAX_ROWS C 10
d i s 10i 0
d i s 10i 0
d getRows s 10i 0 inz(MAX_ROWS)
d getRows s 10i 0 inz(MAX_ROWS)
d data Ds dim(MAX_ROWS) qualified
d data Ds dim(MAX_ROWS) qualified
d deptNo 3a
d deptNo 3a
d deptName 36a varying
d deptName 36a varying
/include STANDARD
/include STANDARD
/free
/free
exec SQL declare C1 scroll cursor for
exec SQL declare C1 scroll cursor for
select deptNo, deptName from department order by deptNo
select deptNo, deptName from department order by deptNo
for read only;
for read only;
exec SQL open C1;
exec SQL open C1;
exec SQL fetch first from C1 for :getRows rows into :data ;
exec SQL fetch first from C1 for :getRows rows into :data ;
for i = 1 to SQLERRD(3);
for i = 1 to SQLERRD(3);
dsply ('Normal ' + data(i).deptNo + ' ' + data(i).deptName);
dsply ('Normal ' + data(i).deptNo + ' ' + data(i).deptName);
endFor;
endFor;
exec SQL close C1;
exec SQL close C1;
*inLR = *on;
*inLR = *on;
H option(*srcStmt : *noDebugIO)
H option(*srcStmt : *noDebugIO)
d MAX_ROWS C 3
d MAX_ROWS C 3
d i s 10i 0
d i s 10i 0
d getRows s 10i 0 inz(MAX_ROWS)
d getRows s 10i 0 inz(MAX_ROWS)
d data Ds dim(MAX_ROWS) qualified
d data Ds dim(MAX_ROWS) qualified
d deptNo 3a
d deptNo 3a
d deptName 36a varying
d deptName 36a varying
/include STANDARD
/include STANDARD
/free
/free
exec SQL declare C1 scroll cursor for
exec SQL declare C1 scroll cursor for
select deptNo, deptName from department order by deptNo
select deptNo, deptName from department order by deptNo
for read only;
for read only;
exec SQL open C1;
exec SQL open C1;
Ahem!
Ahem! doU SQLCODE <> 0;
doU SQLCODE <> 0;
exec SQL fetch relative 1 from C1 for :getRows rows into :data ;
exec SQL fetch relative 1 from C1 for :getRows rows into :data ;
for i = 1 to SQLERRD(3);
for i = 1 to SQLERRD(3);
dsply ('Sequential ' + data(i).deptNo + ' ' + data(i).deptName);
dsply ('Sequential ' + data(i).deptNo + ' ' + data(i).deptName);
endFor;
endFor;
endDo;
endDo;
exec SQL close C1;
exec SQL close C1;
*inLR = *on;
*inLR = *on;
H option(*srcStmt : *noDebugIO)
H option(*srcStmt : *noDebugIO)
d MAX_ROWS C 11
d MAX_ROWS C 11
d pageSIze s 10i 0 inz(MAX_ROWS)
d pageSIze s 10i 0 inz(MAX_ROWS)
/include STANDARD
/include STANDARD
/free
/free
dsply 'Number of rows per page: ' ' ' pageSize;
dsply 'Number of rows per page: ' ' ' pageSize;
if (pageSize > (MAX_ROWS-1));
if (pageSize > (MAX_ROWS-1));
pageSize = (MAX_ROWS-1);
pageSize = (MAX_ROWS-1);
endIf;
endIf;
declareAndOpen();
declareAndOpen();
getRows(pageSize);
getRows(pageSize);
closeCursor();
closeCursor();
*inLR = *on;
*inLR = *on;
/end-Free
/end-Free
p getRows...
p p getRows... b
dp PIb
d dpageSize PI 10i 0 const the
the requested
requested Page
Page Size
Size
d pageSize 10i 0 const
d data Ds dim(MAX_ROWS) DS
DS array
array for
for the
the fetch
fetch
d d data Ds dim(MAX_ROWS)
qualified
d d deptNo 3a qualified
d d deptName
deptNo 3a varying
36a
d deptName 36a varying
d i s 10i 0
d ddirection
i ss 10i 0inz('F')
1a paging
paging direction
direction
d dgetPageSize
direction ss 1a0 inz('F')
10i rows
rows to
to retrieve
retrieve on
on the
the fetch
fetch
d getPageSize
d relativeRow ss 10i 0 0inz(1)
10i
relative
relative offset
offset for
for next
next read
read
d dbackRows
relativeRow ss 10i0 0 inz(1)
10i number
number of
of rows
rows fetched
fetched
d dlastRow
backRows ss 10i0 0
10i status
status for
for EOF
EOF
d lastRow s 10i 0
/free
/free
doU (direction = 'E');
doU (direction= =pageSize
'E'); no.
getPageSize + 1; no. of
of rows
rows to
to retrieve
retrieve
getPageSize = pageSize + 1; Page
if (direction = 'B'); Page back?
back?
ifrelativeRow
(direction = = (1
'B');
- (pageSize + backRows)); offset
offset to
to start
start of
of previous
previous page
page
relativeRow = (1 - (pageSize + backRows));
endIf;
endIf; Fetch
exec SQL fetch relative :relativeRow from C1 Fetch page
page
exec SQL fetch relative :relativeRow
for :getPageSize rows into from C1
:data;
for :getPageSize rows into :data; Store rows retrieved
backRows = SQLERRD(3); Store rows retrieved
backRows = diagnostics
SQLERRD(3); Check
exec SQL get Check for
for EOF
EOF
exec SQL get diagnostics
:lastRow = DB2_LAST_ROW;
relativeRow :lastRow
= 0; = DB2_LAST_ROW; Assume
Assume next
next relative
relative offset
offset
ifrelativeRow
(lastRow = =100);
0; EOF?
EOF?
ifdsply
(lastRow = 100);
('Reached EOF');
dsply ('Reached EOF'); offset
relativeRow = (1 - backRows); offset to
to start
start of
of this
this page
page
relativeRow
endIf; = (1 - backRows);
endIf;
if (backRows = 0);
ifexec
(backRows = 0);
SQL fetch first from C1 for :getPageSize rows into :data;
exec SQL= fetch
backRows first from C1 for :getPageSize rows into :data;
SQLERRD(3);
backRows
endIf; = SQLERRD(3);
endIf;
for i = 1 to backRows;
for i = ('Paging
dsply 1 to backRows;
' + data(i).deptNo + ' ' + data(i).deptName);
dsply ('Paging ' + data(i).deptNo + ' ' + data(i).deptName);
endFor;
endFor;
dsply 'Direction (F/B/E) ' ' ' direction ;
dsply 'Direction (F/B/E) ' ' ' direction ;
endDo;
endDo;
/end-Free
p /end-Free e
p e
/include STANDARD
/free
dsply 'Number of rows per page: ' ' ' pageSize;
if (pageSize > (MAX_ROWS-1));
pageSize = (MAX_ROWS-1);
endIf;
declareAndOpen();
getRows(pageSize);
closeCursor();
*inLR = *on;
/end-Free
p declareAndOpen...
p b
d PI
/free
exec SQL declare C1 scroll cursor for
select deptNo, deptName from department order by deptNo
for read only;
exec SQL open C1;
/end-Free
p e
03/11/11 29
p getRows...
p b
d PI
d pageSIze 10i 0 const
d i s 10i 0
d direction s 1a inz('F')
d getPageSize s 10i 0
d relativeRow s 10i 0 inz(1)
d backRows s 10i 0
d lastRow s 10i 0
/free
doU (direction = 'E');
getPageSize = pageSize + 1;
if (direction = 'B');
relativeRow = (1 - (pageSize + backRows)) ;
endIf;
exec SQL fetch relative :relativeRow from C1
for :getPageSize rows into :data;
backRows = SQLERRD(3);
exec SQL get diagnostics :lastRow = DB2_LAST_ROW;
03/11/11 30
if (backRows = 0);
exec SQL fetch first from C1 for :getPageSize rows into :data;
backRows = SQLERRD(3);
endIf;
for i = 1 to backRows;
dsply ('Paging ' + data(i).deptNo + ' ' + data(i).deptName);
endFor;
dsply 'Direction (F/B/E) ' ' ' direction ;
endDo;
/end-Free
p e
p closeCursor...
p b
d PI
/free
exec SQL close C1;
/end-Free
p e
03/11/11 31
d MAX_ROWS C 100
d MAX_ROWS C 100
d numOrderDetails...
d numOrderDetails...
d s 10i 0
d s 10i 0
d orderHeader e ds extName(ORDHEAD) qualified
d orderHeader e ds extName(ORDHEAD) qualified
d orderDetail e ds extName(ORDDETL) qualified
d orderDetail e ds extName(ORDDETL) qualified
d dim(MAX_ROWS)
d dim(MAX_ROWS)
/free
/free
exec SQL set option naming = *SYS, datFmt = *ISO, datSep = '-';
exec SQL set option naming = *SYS, datFmt = *ISO, datSep = '-';
exec SQL insert into ORDHEAD values( :orderHeader);
exec SQL insert into ORDHEAD values( :orderHeader);
if (SQLCODE = 0);
if (SQLCODE = 0);
exec SQL insert into ORDDETL :numOrderDetails rows
exec SQL insert into ORDDETL :numOrderDetails rows
values (:orderDetail);
values (:orderDetail);
endIf;
endIf;
if (SQLCODE = 0);
if (SQLCODE = 0);
exec SQL commit;
exec SQL commit;
else;
else;
exec SQL rollBack;
exec SQL rollBack;
endIf;
endIf;
A UNIQUE
A UNIQUE
A R EMPLOYEER
A R EMPLOYEER
A EMPID 7A
A EMPID 7A
A NAME 30A
A NAME 30A
A GRADE 2A
A GRADE 2A
A BIRTHDATE L ALWNULL
A BIRTHDATE L ALWNULL
A JOINEDDATE L ALWNULL
A JOINEDDATE L ALWNULL
A SALARY 13P 2 ALWNULL
A SALARY 13P 2 ALWNULL
d deptNo s 3a
d deptNo s 3a
d deptName s 20a varying
d deptName s 20a varying
d mgrNo s 6a
d mgrNo s 6a
d mgrNoNull s 5i 0
d mgrNoNull s 5i 0
exec SQL fetch next from C1
exec SQL fetch next from C1
into :deptNo, :deptName, :mgrNo :mgrNoNull;
into :deptNo, :deptName, :mgrNo :mgrNoNull;
dsply ('Simple ' + deptNo + ' ' + deptName + ' ' + mgrno +
dsply ('Simple ' + deptNo + ' ' + deptName + ' ' + mgrno +
' ' + %char(mgrNoNull));
' ' + %char(mgrNoNull));
d data ds qualified
d data ds qualified
d deptNo 3a
d deptNo 3a
d deptName 20a varying
d deptName 20a varying
d mgrNo 6a
d mgrNo 6a
d dataNull s 5i 0 dim(3)
d dataNull s 5i 0 dim(3)
exec SQL fetch next from C1 into :data :dataNull;
exec SQL fetch next from C1 into :data :dataNull;
dsply ('DS ' + data.deptNo + ' ' + data.deptName + ' ' +
dsply ('DS ' + data.deptNo + ' ' + data.deptName + ' ' +
data.mgrno + ' ' + %char(dataNull(3)));
data.mgrno + ' ' + %char(dataNull(3)));
d empNo s 6a
d empNo s 6a
d hireDate s d datFmt(*MDY/)
d hireDate s d datFmt(*MDY/)
d birthDate s d datFmt(*MDY/)
d birthDate s d datFmt(*MDY/)
/free
/free
exec SQL Set Option Commit=*NONE, Naming=*SYS, DatFmt=*MDY, DatSep='/' ;
exec SQL Set Option Commit=*NONE, Naming=*SYS, DatFmt=*MDY, DatSep='/' ;
exec SQL declare C1 scroll cursor for
exec SQL declare C1 scroll cursor for
select empno, hireDate, birthDate from employee order by empno
select empno, hireDate, birthDate from employee order by empno
for read only;
for read only;
exec SQL Open C1;
exec SQL Open C1;
exec SQL fetch next from C1 into :empNo, :hireDate: birthDate ;
exec SQL fetch next from C1 into :empNo, :hireDate: birthDate ;
d empNo s 6a
d empNo s 6a
d hireDate s d
d hireDate s d
d birthDate s d
d birthDate s d
exec SQL fetch next from C1 into :empNo, :hireDate: birthDate ;
exec SQL fetch next from C1 into :empNo, :hireDate: birthDate ;
d data Ds qualified
d data Ds qualified
d empNo 6a
d empNo 6a
d hireDate d
d hireDate d
d birthDate d
d birthDate d
exec SQL fetch next from C1 into :data ;
exec SQL fetch next from C1 into :data ;
d MAX_ROWS C 100
d MAX_ROWS C 100
d pageSize s 10i 0 inz(MAX_ROWS)
d pageSize s 10i 0 inz(MAX_ROWS)
d data Ds dim(MAX_ROWS) qualified
d data Ds dim(MAX_ROWS) qualified
d empNo 6a
d empNo 6a
d hireDate d datFmt(*ISO)
d hireDate d datFmt(*ISO)
d birthDate d datFmt(*ISO)
d birthDate d datFmt(*ISO)
DATFMT/DATSEP
DATFMT/DATSEP mustmust NOT
NOT
exec SQL Set Option Commit=*NONE, Naming=*SYS; be
be specified
specified
exec SQL Set Option Commit=*NONE, Naming=*SYS;
exec SQL fetch first from C1 for :pageSize rows into :data;
exec SQL fetch first from C1 for :pageSize rows into :data;
CRTSQLRPGI
CRTSQLRPGI OBJ(PGM)
OBJ(PGM) DATFMT(*ISO)
DATFMT(*ISO) DATSEP(-)
DATSEP(-)
Summary ComCon
Ground covered
Keys to Embedded SQL
Writing SQL to Embed
- Tools
- Methodology
Controlling CRTSQLRPGI
SQLCA and SQLCODE considerations
Getting data without SELECT
- GET DIAGNOSTICS
- VALUES INTO
Mastering Multi Row Fetch
- Page at a time processing
Handling NULL
Dates, Times and Timestamps