SQL Tips & Techniques

Fred Gamache

Agenda
Query Manager  SQL Syntax  Embedded SQL  Stored Procedures  Performance 

30 Second Bio 
 

 

Started on S/38 in 1986 ± in consulting since 1989 Worked on AS/400 doing primarily RPG application development and support Written a few articles for AS/400 magazines Started Independent Consulting in 2003 Currently using 
 

DB2 ± RPG ± SQL Oracle ± PL/SQL SQL Server ± VB.Net and ASP.Net

Goals & Assumptions 


Assuming a basic knowledge of SQL syntax. My goal is to give you some tips and techniques that you can use tomorrow. Stop me if you¶re not clear on something Presentation can be downloaded from
www.gamacheconsulting.com 



Query Manager

Query Manager vs. Query Manager and SQL Developers Kit 
 

  

Query Manager Comes with every iSeries Can create a QM object based on a source member containing a SQL statement No front end ± just a command interface No green screen Interactive SQL Cannot compile a program with embedded Can Execute a program that has been compiled with Embedded SQL 

  

Developers Kit Separate chargeable product QM has a front end similar to Query/400 STRSQL ± gives you the ability to create an SQL statement via a prompted interface Ability to compile programs with Embedded SQL

Query Manager 

No front end ± just a command interface 


CRTQMQRY ± create STRQMQRY - execute 

 

Create an object from a source file member Source can contain any single valid SQL statement Compilation and Execution are separate steps ± just like a program

Query Manager ± Create QM Query
Create Query Management Query (CRTQMQRY)
Type choices, press Enter. Query management query Library . . . . . . Source file . . . . . Library . . . . . . Source member . . . . Text 'description' . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Name Name, *CURLIB Name Name, *LIBL, *CURLIB Name, *QMQRY *CURLIB QQMQRYSRC *LIBL *QMQRY *SRCMBRTXT *SRC *LIBL *SRC

Sort sequence . . . . . . . . . Library . . . . . . . . . . . Language ID . . . . . . . . . .

Name, *SRC, *JOBRUN, *JOB... Name, *LIBL, *CURLIB *JOB, *JOBRUN...

Additional Parameters Authority . . . . . . . . . . . Replace object . . . . . . . . . *LIBCRTAUT *YES Name, *USE, *CHANGE, *ALL... *YES, *NO

Query Manager ± Start QM Query
Start Query Management Query (STRQMQRY) Type choices, press Enter. Query management Library . . . Output . . . . . Query management Library . . . query . . . . . . . . . . . . . . . report form . . . . . . . . . . . . . . . . Name Name, *LIBL, *CURLIB *, *PRINT, *OUTFILE Name, *SYSDFT, *QMQRY Name, *LIBL, *CURLIB

*LIBL * *SYSDFT

Additional Parameters Relational database . Connection Method . . User . . . . . . . . . Password . . . . . . . Naming convention . . Allow information from . . . . . . . . . . . . . . . . . . . . QRYDFN . . . . . . *NONE *DUW *CURRENT *SYS *NO

*DUW, *RUW Name, *CURRENT Character value, *NONE *SYS, *SQL, *SAA *NO, *YES, *ONLY

Set variables: Variable name . . . . . . . . Variable value . . . . . . . .

Using Query Manager in PDM 

Create a source file QQMQRYSRC 

(use length of 91) 

 

WRKMBRPDM on your QM Source Use F16 in PDM to go to User Defined Option Create these options
QC QR CRTQMQRY QMQRY(&L/&N) SRCFILE(&L/&F) STRQMQRY QMQRY(&L/&N) 

Enter an SQL statement in a source member, then use the QC PDM option to compile it, then QR to execute it

Prompted QM Queries 
  

Gives you the ability to create an object that will prompt you at run time to fill in the parameter Interactively you get prompted In a CL program you can set a variable in your program Variables should  

Be prefixed with a ³&´ Should be UPPER case
SELECT DISTINCT &FIELD FROM &LIB/&FILE ORDER BY &ORDERBY 

Can replace any part of your SQL statement
³Type a value for variable ³FIELD" and press Enter. ³

Prompted QM Queries Examples
Select * from ordhead where ordstat = µO¶ and custid = &CUSTOMER Select * from custmast where cusnam like &CUSNAME
You need to include the quotes into the value passed to Query Manager ± When prompted, you¶d enter: µCPCU%¶

Passing Parms from a CL Program 
 

CL variables should be character variables You need to pass in any quotes around character fields Sample CL statement
STRQMQRY QMQRY(TESTQRY) OUTPUT(*PRINT) + SETVAR((FROM &FDATEA) (TO &TDATEA))

Passing Parms from a CL Program
DCL RTVJOBA CVTDAT STRQMQRY VAR(&CDATE) TYPE(*CHAR) LEN(8) CYMDDATE(&JDATE) DATE(&JDATE) TOVAR(&CDATE) FROMFMT(*CYMD) + TOFMT(*YYMD) TOSEP(*NONE) QMQRY(SHPPRT) OUTPUT(*OUTFILE) + OUTFILE(SHIPPF) SETVAR((FDATES &CDATE) + (TDATES &CDATE)) 

SDATE is a numeric field so no quotes are necessary SELECT SUM(SHPQTY) FROM SHPHST WHERE SDATE BETWEEN &FDATES AND &TDATES

Passing Parms from a CL Program
CL Program ± character field in the SQL
VAR(&LIB10) TYPE(*CHAR) LEN(10) + VALUE('1234567890') DCL VAR(&LIB12) TYPE(*CHAR) LEN(12) CHGVAR VAR(&LIB12) VALUE(''' *TCAT &LIB10 *TCAT ''') STRQMQRY QMQRY(TESTQM) SETVAR((FROMLIB &LIB12)) PGM DCL

4 single quotes

Query Manager source
select * from dspobjdpf where odlbnm = &FROMLIB

Retrieving Source from a Query/400 query   

The Retrieve QM Query command will retrieve the SQL source from a Query/400 object Puts the SQL used in a Query/400 query into a source file so you can then view it, modify it, and create a QM Query from it. Can also use this to replace a static Query with a prompted Query Manager query

Retrieve QM Query Command
Retrieve Query Mgmt Query (RTVQMQRY) Type choices, press Enter. Query management query Library . . . . . . Source file . . . . . Library . . . . . . Source member . . . . Allow information from . . . . . . . . . . . . . . . . . . . . QRYDFN . . . . . . Name Name, *LIBL, *CURLIB Name Name, *LIBL, *CURLIB Name, *QMQRY *NO, *YES, *ONLY

*LIBL *LIBL *QMQRY *NO

How to find Queries that use a file
PGM DCL DCL DCLF DLTF MONMSG DLTF MONMSG CRTSRCPF DSPOBJD BEGIN: PARM(&LIBRARY &FILE) VAR(&LIBRARY) TYPE(*CHAR) LEN(10) VAR(&FILE) TYPE(*CHAR) LEN(10) FILE(QTEMP/QRYOBJS) FILE(QTEMP/QRYOBJS) CPF0000 FILE(QTEMP/&LIBRARY) CPF0000

FILE(QTEMP/&LIBRARY) OBJ(&LIBRARY/*ALL) OBJTYPE(*QRYDFN) + DETAIL(*FULL) OUTPUT(*OUTFILE) + OUTFILE(QTEMP/QRYOBJS) RCVF /* GET QUERY NAME AND LIBRARY NAME */ /* IF END OF FILE REACHED, EXIT LOOP */ MONMSG CPF0864 EXEC(GOTO EOF) RTVQMQRY GOTO QMQRY(&ODLBNM/&ODOBNM) + SRCFILE(QTEMP/&LIBRARY) ALWQRYDFN(*ONLY) CMDLBL(BEGIN)

EOF:

FNDSTRPDM STRING(&FILE) FILE(QTEMP/&LIBRARY) MBR(*ALL) OPTION(*NONE) PRTMBRLIST(*YES) ENDPGM

SQL Syntax Tips

Join methods ± Inner Join
Inner ± selects only records where a match exists in both tables
Select a.dept, b.depnam from slshdr a inner join depmst b on a.dept = b.dept

Select a.dept, b.depnam from slshdr a, depmst b where a.dept = b.dept

Join Methods ± Outer Join
Outer ± selects all records from primary table even if a match does not exist in the secondary table.
Select a.dept, b.depnam from slshdr a left outer join depmst b on a.dept = b.dept

Join Methods ± 3+ tables Joining with three tables
Select * From slshdr a inner join slsdet c on a.ordnum = c.ordnum inner join depmst b on a.dept = b.dept

Join Methods ± Exception Join
Find Orders with a department not in the department master select * from slshdr a exception join depmst b on a.dept = b.dept select * from slshdr a where a.dept not in (select dept from depmst)

Joining a file to itself
select * from empmst a inner join join empmst b on a.supervisorid = b.empid

The UNION Statement 

This takes the results of two SQL statements and combines the output, in effect merging the two result sets 


Details and totals Merge active table and history table  



The fields in both statements must have the same attributes (char, decimal, etc.) Field names do NOT need to be the same Must have the same number of fields in both statements

The Union Statement Examples 

Using UNION to get details and totals

Select µOrder¶ as rowtype, order, price, extprice From custord Union Select µTotal¶ as rowtype, 0 as order, 0, sum(extprice) From custord Order by rowtype, order 

Using Union to merge two tables 

Field names will be from the first table referenced

Select ordnum, cust, ordamt from orders Union Select ordnum, cust, totamt from orderhist

Alter Table   

Use Alter Table to add, delete or change a column in a table. You do NOT need to manually save the data, it does it for you Example:
Alter Table Customer Add contact char(30) 

If you add a column with ³Not Null´, you must specify a default value

Alter Table 

If you Drop a column you receive a CPF warning that you must answer
Change of file TEST1 may cause data to be lost. (C I) 

This can be a problem if you¶re running the Alter Table in a client server application, through ODBC for example.

Alter Table ± Drop Field 

You need to manipulate the system reply list to answer that message

call qsys.qcmdexc( 'ADDRPYLE SEQNBR(3333) MSGID(CPA32B2) RPY(''I'')',0000000045.00000) CALL QSYS.QCMDEXC('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000) Alter table x drop column A call qsys.qcmdexc( 'RMVRPYLE SEQNBR(3333)',0000000021.00000) CALL QSYS.QCMDEXC('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)

Using a Select in a FROM Clause  



Where you would normally use a Table name in a From clause ± you can use a full SELECT statement Useful to avoid having to create a View Useful if you are using embedded SQL and the want to include host variables in the FROM

Using a Select in a FROM Clause - Example 

Basic Style
SELECT ordnum, ordval FROM ordhdr a inner join (select ordnum, qty*price as ordval from orddtl) b on a.ordnum = b.ordnum 

In an RPG program
SELECT ordnum, ordval FROM ordhdr a inner join (select ordnum, qty*price as ordval from orddtl Where status = :linsts) b on a.ordnum = b.ordnum 

Get a count of distinct values in a table
Select count(*) from (select distinct custnum from orders) a

Join fields with different attributes  



Creating a Join LF using DDS or doing a join in Query/400, the join fields must have the same attributes Not a requirement using SQL Fields can be converted on the fly using built in functions

Join fields with different attributes - Example
If ordnum is decimal in slshdr and ordnum is character is slsdet then you CAN¶T join them in Query/400 Use a built in function to convert one of the values select * from slshdr a left outer join slsdet b on a.ordnum = decimal(b.ordnum,6,0)

Subqueries   

Subqueries are queries nested inside other queries, marked off with parentheses. Most often, you see subqueries in WHERE or HAVING clauses. Subqueries only need to be evaluated once

Subqueries ± Examples
select ordnum, price from slsdet where price > (select avg(price) from slsdet) order by price

Correlated Subqueries    

Just like a regular subquery with some additional features You can refer to a field from the outer SQL statement within it Will need to be evaluated for each row returned Can be performance issues

Correlated Subqueries ± Examples
Select ordnum, price, From slsdet a Where price > (select avg(price) from slsdet b where a.cust = b.cust)

COALESCE 


The COALESCE function returns the value of the first non-null expression. Useful anytime you have the possibility of having a null value
SELECT DEPTNO, DEPTNAME, COALESCE(MGRNO, ¶ABSENT¶), ADMRDEPT FROM DEPARTMENT

Updating Data from Another Table 
 

Join logical files cannot be updated SQL statements using a join cannot be updated You can however, update a value from one table to another

Updating Data from Another Table ± Example
update slshdr set dept = (select dept from depmst where depnam = 'IT') where dept = 40

update slshdr a set ordervalue = (select coalesce(sum(price * orderquantity),0) from slsdet b where char(a.ordnum) = b.ordnum)

Updating Multiple Fields with Data from Another Table ± Example
update myfile a set (field1, field2)= (select b.field1, b.field2 from file2 b where a.key1=b.key1 and a.key2=b.key2) where exists (select c.key1 from file2 c where a.key1=c.key1 and a.key2=c.key2)

Char vs. Digits 


CHAR strips leading zeros, DIGITS doesn't. If you have a NUMERIC(5,0) number equal to 00044: 


CHAR would give '44', DIGITS would give '00044'.

Case insensitive searching 

Built-in functions ± UPPER and UCASE
Select * from custmst

Where upper(cusname) = upper(:fieldx) 

LOWER and LCASE perform comparable function Will prevent optimizer from using any indexes unless the index was created with TRNTBL, ALTSEQ or *LANGIDSHR on the index create. There are examples of using indexes with translate table in the Database Performance and Query Optimization book. 

Using CASE 
 

Works similar to an RPG CASE If there is no ELSE clause ± you can get a NULL result Evaluated in the order listed
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, CASE WHEN EDLEVEL < 15 THEN ¶SECONDARY¶ WHEN EDLEVEL < 19 THEN ¶COLLEGE¶ ELSE ¶POST GRADUATE¶ END FROM EMPLOYEE

Using the CASE expression
Select orddate, Case Substr( Digits( orderdate ), 1, 2 ) When '01' Then 'JAN' When '02' Then 'FEB' When '03' Then 'MAR' When '04' Then 'APR' When '05' Then 'MAY' When '06' Then 'JUN' When '07' Then 'JUL' When '08' Then 'AUG' When '09' Then 'SEP' When '10' Then 'OCT' When '11' Then 'NOV' When '12' Then 'DEC' Else µxxx' End From slshdr

More uses for CASE 

Useful to prevent Divide by 0 errors
Select ordnum, price, Case when cost = 0 then 0 Else price/cost End as markup From slsdet

Creating tables with Long Field Names 

First use the CREATE TABLE statement to specify the long name (customer_master)
The iSeries file name (not the table) is now
CUSTO00001

CREATE TABLE customer_master (customer_name FOR COLUMN cusnam CHAR (20), customer_city FOR COLUMN cuscty CHAR(40))  

Then RENAME TABLE statement to also assign a short name (cusmst) for the non-SQL interfaces:

RENAME TABLE customer_master TO SYSTEM NAME cusmst

Using multi-member files 

If you want to identify a particular member within a file, use the following SQL command:
CREATE ALIAS your-alias FOR your-library/your-file (yourmember) 

Then use standard SQL referencing the alias
SELECT * FROM your-alias.

Retrieve top n number of records 

Syntax only works on V5R1 and up
select * from myLib/myFile fetch first 10 rows only

Accessing a remote database with Connect    

Can be useful if you have SQL Developers kit on one iSeries but not another one that you want to query Need to ADDRDBDIRE ± Relational Database Directory Entry first Then use CONNECT in SQL to connect to a remote SQL database. Additional program products can give you the ability to connect to Oracle, SQL Server, etc
C/exec sql C+ connect to :host user :orauser using :pwd C/end-exec

Date Arithmetic 

A couple of steps ± but all done in one SQL statement 
  

Convert numeric fields to character Format the character field to look like a DATE field Use the DATE function to make it a DATE data type Perform your Date arithmetic

Date Arithmetic 

Add to a date

select order_date, date('20' || substr(digits(order_date),1,2) || '-' || substr(digits(order_date),3,2) || '-' || ORDER_DATE substr(digits(order_date),5,2) ) + 20 days 40,415 from slsdet select order_date, date('20' || substr(digits(order_date),1,2) || '-' || substr(digits(order_date),3,2) || '-' || substr(digits(order_date),5,2) ) + 1 month from slsdet

Date expression 05/05/04

ORDER_DATE 40,415

Date expression 05/15/04

Date Arithmetic 

Subtract two Numeric Date fields ± numeric in database, but contain dates

select order_date, ship_date, Days(date('20' || substr(digits(ship_date),1,2) || '-' || substr(digits(ship_date),3,2) || '-' || substr(digits(ship_date),5,2) )) Days(date('20' || substr(digits(order_date),1,2) || '-' || substr(digits(order_date),3,2) || '-' || substr(digits(order_date),5,2) ORDER_DATE )) from slsdet
40,415 

SHIP_DATE 40,516

Numeric expression 31

Result is in Days ± 31 days

Date Arithmetic 

Subtract two Numeric Date fields ± numeric in database, but contain dates

select order_date, ship_date, date('20' || substr(digits(ship_date),1,2) || '-' || substr(digits(ship_date),3,2) || '-' || substr(digits(ship_date),5,2) ) date('20' || substr(digits(order_date),1,2) || '-' || substr(digits(order_date),3,2) || '-' || substr(digits(order_date),5,2) ORDER_DATE ) from slsdet
40,415 

SHIP_DATE 40,516

Numeric expression 101

Result is in Months and Days ± 1 month and 1 day

Date Arithmetic ± Selecting Dates 

Odcdat = 6 position character field containing a date ± YYMMDD

SELECT date(substr(odcdat,3,2) || '/' || substr(odcdat,5,2) || '/20'|| substr(odcdat,1,2)) FROM dspobjpf where odcdat <> ' ' and date(substr(odcdat,3,2) || '/' || substr(odcdat,5,2) || '/20'|| substr(odcdat,1,2)) < current date - 25 days

Embedded SQL

SQLCA Data Structure 
  

When a SQL statement fails, it will not generate a CPF error. An SQLCA is a set of variables that is updated at the end of the execution of every SQL statement. Brought in automatically by the compiler (when type = SQLRPGxx) DS updated when a SQL statement completes ± successfully or unsuccessfully 

Generally ± you should check SQLSTT after every SQL statement SQLCOD = result code SQLSTT = result state -± message number SQLER3 = Number of rows modified by the statement 

Key fields for our discussion are: 
  

Complete details in the SQL Reference book ± Appendix B

Compile Options   

Commitment Control option  Only affects SQL commands, not RPG Updates, etc.  If it¶s not *NONE ± then your tables had better be journalled Precompiler options to specify the naming convention used If you are connecting to non-iSeries databases, you must use SQL naming

The Basics of Reading via SQL 

Use an external data structure to define the fields in the RPG 

Not required ± but it can simplify defining the fields you are going to read 

   

Declare the cursor ± must be prior to the Open in the source Open the cursor Fetch the next record and load data from the cursor into RPG variables Repeat that Fetch until End of File is found, indicated by SQLSTT = µ02000¶ Close the Cursor

The Basics of Reading via SQL
**************************************** ********************** * Sample program to read selected fields from file via SQL **************************************** ********************** * This defines all the fields in the record D InRec e ds extname(pfdata) C/exec sql C+ declare c1 cursor for C+ select odobnm, odlbnm from pfdata C/end-exec C/exec sql C+ open c1 C/end-exec C/exec sql C+ fetch c1 into :odobnm, :odlbnm C/end-exec C '00000' * dou sqlstt <>

Do something with each record

C/exec sql C+ fetch c1 into :odobnm, :odlbnm C/end-exec C C C/exec sql C+ close c1 C/end-exec C *inlr move *on enddo

Update using a Variable 
 

Only slightly more complex than reading Uses an RPG program variable in the SQL statement Variables are listed in the RPG as :varname

Update using a Variable
************************************************************** * Sample program to run a single SQL statement using * static SQL with a parameter ************************************************************** D Parm1 s 6a CALL PGM(SQL2) D Parm2 s 10a C C C *entry plist parm parm

Sample program call:
PARM(µTEST' 'MYLIB')

parm1 parm2

C/exec sql C+ update pfdata set ODDDAT = :parm1 C+ where ODLBNM = :parm2 C/end-exec /free if sqlstt <> '00000'; // handle the error condition else; // completed normally - show how many records were updated dsply sqler3; endif; *inlr = *on; /end-free

Execute Immediate    

Useful when you need to build your SQL statement on the fly based on variables or parameters Need to include any quotes, etc ± the SQL needs to be syntactically correct You should be able to paste it into an Interactive SQL session and execute it Get your quotes correct!

Execute Immediate
************************************************************** * Sample program to run a single SQL statement using an * EXECUTE IMMEDIATE after building the SQL on the fly ************************************************************** ***** DParm1 DSQLStmt D C C /free // Build the SQL statement to be executed SQLStmt = %trim(SQLStmt) + parm1; /end-free *entry call sql3 '''abc''' s s 10a 100a

inz('Update pfdata set odddat = ')

plist parm

parm1

C/exec sql C+ execute immediate :SQLStmt C/end-exec /free if sqlstt <> '00000'; // handle the error condition else; // completed normally - show how many records were updated dsply sqler3; endif; *inlr = *on; /end-free

RPG Tips 

When using SQL with LIKE and RPG variables make sure you use %TRIM 

RPG variables will be blank padded 

Use a capital C for the Spec and you can press F4 to prompt it ± won¶t prompt with a lower case C but it will compile
COMMIT compile option ± default value is *CHG  

Set that value through SQL in the code each time it executes
c/exec sql + Set Option DatFmt=*ISO, Commit=*None, CloSQLCsr=*EndMod c/end-exec

Using a Host Indicator to flag Null values or data errors 
 

The format is -> :host-identifier INDICATOR :host-indicator Can be used in SELECT INTO, FETCH, SET variable, VALUES INTO The indicator can specify the following: 


Null value was returned ± indicator = -1 Null value due to data mapping error ± indicator = -2 
      

Characters could not be converted Numeric conversion error (underflow or overflow) Arithmetic expression error (division by 0) Date or timestamp conversion error (a date or timestamp that is not within the valid range of the dates for the specified format) String representation of the datetime value is not valid Mixed data not properly formed A numeric value that is not valid Argument of SUBSTR scalar function is out of range 



Original length of a truncated string Record the seconds portion of a time if the time is truncated on assignment to a host variable.

Using a Host Indicator to flag Null values or data errors
D D D D D D D D MaxSize AvgSize MaxTxt DivVal Ind_avg Ind_max Ind_txt Ind_div s s s s s s s s 15s 15s 30a 15s 5I 5I 5I 5I 0 0 0 0 0 0 0

C/exec sql C+ select avg(odobsz), max(odobsz), max(odobtx), 9/0 C+ into :avgsize :Ind_avg, :maxsize :Ind_Max, C+ :maxtxt :Ind_txt, :divval :ind_div C+ from pfdata C/end-exec

Stored Procedures and User Defined Functions

What is a Stored Procedure? 
  

SQL¶s version of a program call The application waits for the Proc to complete before continuing Parameters can be passed back and forth Can be executed on a local or remote system

Benefits of Stored Procs 
 

Very useful in a distributed application ± the Stored Proc can be called once from the application and perform multiple updates Network traffic can be reduced ± multiple rows read on the server and only one summary returned to the client Can be used to control access to secured objects 

Users can access the procedure but not the database table it is based on  

Have the ability to re-use your existing programs within new SQL applications Can return a result set to a client application 

Can¶t return a result set to an RPG program

Two Types of Stored Procedures 

SQL  Written using SPL (SQL Procedure Language) External  Written in any iSeries programming language including Java 

External Stored Procedures 

Written in any iSeries programming language 

RPG, COBOL, etc.    

 

CREATE PROCEDURE is run in SQL to identify the *PGM object to the database An External Procedure does not have to contain any SQL statements. It can be any existing program on your system. A good choice if you have complex processing you want to perform or want to re-use existing code like customer pricing routines or a sales tax routine Must be a *PGM object No display ± must be a batch pgm Compile w/activation group (*CALLER)

External Stored Procedure Example 


Start with an RPG program that accepts parameters and returns a parameter The program is compiled as PRCTST
s s s plist parm parm parm 3p 0 3p 0 6p 0

Dadd1n Dadd2n Dresult C C C C *entry

add1n add2n result

C* /free result = add1n + add2n; return; /end-free

Create the Stored Procedure 
 

Use iSeries Navigator to create it (easiest way) Or enter the source in a source file and then execute the source file using RUNSQLSTM Or execute this command through any other SQL Input and Output interface 

Parameters Interactive, Query Manager, ODBC, etc.

CREATE PROCEDURE PRCTEST ( IN ADD1 DECIMAL(3, 0) , IN ADD2 DECIMAL(3, 0) , OUT "RESULT" DECIMAL(6, 0) ) LANGUAGE RPGLE SPECIFIC PRCTEST EXTERNAL NAME 'PRCTST' PARAMETER STYLE GENERAL ;

Actual name of the program being run

Execute the Stored Procedure 

Execute the stored procedure from within an RPG program using Embedded SQL
result a b an bn *entry s s s s s plist parm parm 6p 0 3a 3a 3p 0 3p 0 a b an bn

d d d d d C C C

c move a c move b C/exec sql C+ CALL PRCTEST (:an, :bn, :Result) C/end-exec c dsply c move *on

result *inlr

SQL Stored Procedures 
  

Written in SQL Language Very similar to SQL Language in other databases which could make it easier to port Code is converted to an ILE C program with embedded SQL Requirements 


Must be on V4R2 or higher V4R2 to V4R5 


Must have SQL Development Kit for iSeries Must have the ILE C Compiler Must have SQL Development Kit for iSeries on the development machine 

V5R1 and higher 

Creating a Procedure with Navigator

Debugging with V5R2 

Use the Debug View option in the proc 

Set Option DbgView =*Source You can also use this option on the RUNSQLSTM command 

Debugging can only be done within the job that created the procedure because the view is stored in QTEMP 

PTF will cause the view to be stored permanently 


V5R1 -- SI06814 V5R2 -- SI06652 

To view the returned result, prior to V5R2 you would have to create a program to call your proc and debug that program In V5R2 you can call a proc from the Run SQL Scripts window in Navigator and the output parms are displayed on the Messages tab. PTF¶s available for V5R1 SIO6359, SIO6310, SIO6358  

Sample from a SQL Procedure
DECLARE CONTINUE HANDLER FOR record_not_found Begin SET at_end = 1; End; SET TOTCOUNT = 0 ; SET at_end = 0; OPEN C2 ; WHILE AT_END = 0 DO FETCH C2 INTO LIBNAME , LIBCOUNT ; SET TOTCOUNT = TOTCOUNT + LIBCOUNT ; END WHILE ; CLOSE C2 ; END ;

Use of QCMD/QCMDEXC 
 

QCMD and QCMDEXC are already registered as a stored procedure QCMD  Will invoke a command line  When you¶re in Interactive SQL and need to run a command, execute the following SQL: CALL QCMD QCMDEXC  Will run any CL command passed to it

CALL QSYS/QCMDEXC ('CHGQRYA QRYTIMLMT(120)', 0000000022.00000) CALL QSYS.QCMDEXC('chgcurlib curlib(fred)',0000000023.00000);

User Defined Functions  



Similar to Stored Procedures, but a function will return a value Can be written in SQL or External (RPG, etc.) Easy to create using Navigator 


Drill down to a library Right click ± New, Function, SQL 

Can also be created in SEU ± in a source file and then executed in SQL

User Defined Functions

User Defined Functions

User Defined Functions

User Defined Functions 

Simplified SQL statement
select a.*, subnumericdates(orddat, shpdat) from slsdet a 

Reusable
Select subnumericdates(invoice_date, payment_date) From ardata 

Details on SQL Language syntax in Stored
Procedures, Triggers and User Defined Functions on DB2 Universal Database for iSeries

Performance

Performance  

Run SQL under debug and review joblog for messages regarding suggested indexes to build. Joblog will contain lots of informative messages including Access Paths that need to be created and suggestions for you to create permanent access paths to speed up processing.

Starting Debug from a Client Application 


Start Debug on the iSeries job from a VB application to generate logging info Use the same philosophy to run an iSeries command from a client application To Start Debug:
set CON1 = server.createobject("ADODB.Connection") set CMD1 = server.createobject("ADODB.Command") /*open the connection */ CON1.Open "DSN=MYAS400;UID=myuser;PWD=mypwd;" cmd1.activeconnection = con1 cmd1.commandtext = "call qsys.qcmdexc('strdbg updprod(*yes)',0000000020.00000)" cmd1.execute /* the above starts debug on the as/400 by calling qcmdexc api to execute cmd strdbg*/ Dim cn1 As New IBM.Data.DB2.iSeries.iDB2Connection cn1.ConnectionString = "DATASOURCE=myas400; UID=myuser;PWD=mypwd" Dim cmd As New IBM.Data.DB2.iSeries.iDB2Command cmd.Connection = cn cmd.CommandText = "call qsys.qcmdexc('strdbg updprod(*yes)',0000000020.00000)" cn.Open() cmd.ExecuteNonQuery() cn.Close() 

To End Debug
cmd1.commandtext = "call qsys.qcmdexc('enddbg',0000000006.00000)³ cmd1.Execute 

Standard debug messages are logged in the QZDASOINIT job running in the QSERVER subsystem

Sample Joblog Messages
call sqltest '123' PREPARE of statement SQLSTRING completed. ODP reused. ODP not deleted. Row not found for UPDATE. DSPLY No records found for TSTLIB1 ODP reused. ODP not deleted. Row not found for UPDATE. DSPLY No records found for TSTLIB2 ODP reused. ODP not deleted. Row not found for UPDATE. DSPLY No records found for TSTLIB3

Sample Joblog Messages
All access paths were considered for file FILEA. Additional access path reason codes were used. All access paths were considered for file FILEB. Additional access path reason codes were used. Access path built for file FILEB. File FILEA processed in join position 1. Access path suggestion for file FILEA. File FILEB processed in join position 2.

Sample Joblog Messages
Additional Message Information Message ID . . . . . . : CPI432F Date sent . . . . . . : 11/12/03 Time sent . . . . . . : 10:27:27 Message . . . . : Access path suggestion for file FILEA. Cause . . . . . : To improve performance the query optimizer is suggesting a permanent access path be built with the key fields it is recommending. The access path will access records from member FILEA of file FILEA in library TSTLIB. In the list of key fields that follow, the query optimizer is recommending the first 1 key fields as primary key fields. The remaining key fields are considered secondary key fields and are listed in order of expected selectivity based on this query. Primary key fields are fields that significantly reduce the number of keys selected based on the corresponding selection predicate. Secondary key fields are fields that may or may not significantly reduce the number of keys selected. It is up to the user to

Resources 
 

www.as400pro.com www.iseriesnetwork.com ± subscription required for articles, forums are free IBM iSeries DB2 manuals 

http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/rzahf/rzahfli0.htm 

Preparing for and Tuning the V5R2 SQL Query Engine on DB2 Universal Database for iSeries Redbook 

http://publib-b.boulder.ibm.com/Redbooks.nsf/RedbookAbstracts/sg246598.html?Open 

Stored Procedures, Triggers and User Defined Functions on DB2 Universal Database for iSeries Redbook  

this is the best resource from IBM that I¶ve found on Stored Procedures
http://publib-b.boulder.ibm.com/Redbooks.nsf/0/93beee575837a66185256e390055723e?OpenDocument 

IBM iSeries Application Development Education 

Contains a number of free online courses on SQL performance 

http://www-1.ibm.com/servers/enable/site/education/ibo/curr_apdev.html?apdv DB2 for iSeries Tips http://www-1.ibm.com/servers/eserver/iseries/db2/db2tips.htm 

Thanks!!!!
Fred Gamache fred@gamacheconsulting.com www.gamacheconsulting.com

Sign up to vote on this title
UsefulNot useful