Este documento es una traducción al castellano del capitulo 6.3 del
Redbook sg245402
realizada por Walter Nasich
SQL en programas RPG
En lugar de usar operaciones de acceso a archivos de base de datos, tales como READ,
CHAIN, UPDATE, y DELETE, podemos incrustar sentencias SQL en nuestros programas RPG IV y
usar estas para procesar registros en los archivos de base de datos del AS/400. SQL es un
estandard para el acceso a base de datos, y es usado por los clientes en diferentes
plataformas.
Algunas razones para el uso de SQL:
SQL es un lenguaje mas natural y su codigo es facil de mantener y leer.
SQL puede simplificar la lógica cuando múltiples registros son incluidos en una
operación, tales como UPDATE o DELETE.
Las operaciones SQL se realizan por un optimizador de consultas, el cual es mejorado con
cada nueva versión, y automáticamente toma las ventajas de las nuevas tencologias de
base de datos.
La migración de aplicaciones desde o al AS/400 es facil si las aplicaciones estan
escritas usando un lenguaje estandard como el SQL
El codigo fuente que contiene sentencias SQL incrustadas debe ser primero procesadas
por un Proprocesador SQL. Este trabajo reemplaza las sentencias SQL con llamadas a los
programas de función correspondientes. Este proprocesador es parte del producto
licenciado DB2 Query Manager y SQL Development Kit for AS/400, el cual debe estar
disponible durante el desarrollo de la aplicación. En tiempo de ejecución el soporte
esta incluido dentro del sistema operativo.
Reglas para el incrustado de sentencias SQL
Use las siguientes reglas cuando escriba un programa RPG IV con sentencias SQL
incrustadas:
Ingrese sus sentencias SQL sobre las especificaciones C.
Comience sus sentencias SQL usando el delimitador /EXEC SQL en las posiciones 7 hasta 15,
con la / en la posición 7.
Puede comenzar ingresando sentencias SQL sobre la misma linea donde comienza el
delimitador o sobre una nueva linea.
Use el delimitador de linea de continuación, un + (signo más) en posición
7, para continuar su sentencias en lineas subsecuentes.
Use el delimitador de final /END-EXEC en las posiciones 7 hasta 15, con la /
barra en posición 7, para señalar el fin de sus sentencia SQL.
Un ejemplo de una sentencia SQL UPDATE incrustada:
C/Exec Sql
C+ Update Parts
C+ Set PartDes = :DspDes,
C+ PartQty = :DspQty,
C+ PartPrc = :DspPrc,
C+ PartDat = :DspDat
C+ Where PartNum = :DspNum C/End-Exec
El miembro fuente que contiene el programa RPG IV con las sentencias SQL incrustadas
debe ser del tipo SQLRPGLE. Esto indica a la opción 14 o 15 del PDM ejecutar el mandato
CTRSQLRPGI, el cual es requerido para llamar al Preprocesador SQL.
Proprocesador SQL
El preprocesador SQL crea un miembro de archivo fuente de salida. Por omisión, este es
creado en un archivo fuente temporario llamado QSQLTEMP1 en la biblioteca QTEMP, el cual
es automáticamente borrado por el sistema al final del trabajo. Puede especificar el
archivo fuente de salida como un nombre de archivo permanente en el mandado del
preprocesador. Un miembro con igual nombre que el programa es agregado al archivo fuente
de salida.
Este miemobro contiene los siguientes items:
Llamadas al soporte de tiempo de ejecuciòn del SQL, el cual remplaza las sentencias SQL
incrustadas.
Sentencias SQL analizadas y con las sintaxis chequeada
Por omisión, el precompilador llama al compilador del lenguaje usando, CRTBNDRPG o
CRTRPGMOD segun la opción del PDM seleccionada.
Manejo de exepciones y errores
SQL no se comunica directamente con el usuario final, pero devuelve codigos de error al
programa de aplicación cuando un error o una excepción ocurre. Estos codigos de error
pueden ser usados de dos maneras:
Chequeando codigos de error en un area de comunicaciones SQL.
Definiendo manejadores globales de error con una sentencia WHENEVER.
Area de cominicaciones SQL
El preprocesador SQL automáticamente incluye el SQLCA (SQL Communication Area) en las
especificaciones D del programa RPG IV antes de las primeras especificaciones C. Por lo
tanto, no es necesario codificar INCLUDE SQLCA en el programa fuente.
El SQLCA, incluido en el programa ILE RPG, contiene los siguientes campos:
D* SQL Communications area
D SQLCA DS
D SQLAID 1 8A INZ(X'0000000000000000')
D SQLABC 9 12B 0
D SQLCOD 13 16B 0
D SQLERL 17 18B 0
D SQLERM 19 88A
D SQLERP 89 96A
D SQLERRD 97 120B 0 DIM(6)
D SQLERR 97 120A
D SQLER1 97 100B 0
D SQLER2 101 104B 0
D SQLER3 105 108B 0
D SQLER4 109 112B 0
D SQLER5 113 116B 0
D SQLER6 117 120B 0
D SQLWRN 121 131A
D SQLWN0 121 121A
D SQLWN1 122 122A
D SQLWN2 123 123A
D SQLWN3 124 124A
D SQLWN4 125 125A
D SQLWN5 126 126A
D SQLWN6 127 127A
D SQLWN7 128 128A
D SQLWN8 129 129A
D SQLWN9 130 130A
D SQLWNA 131 131A
D SQLSTT 132 136A
D* End of SQLCA
Los valores SQLCOD y SQLSTT son puestos por le administrador de base de datos después
de que cada sentencia SQL se ejecuta. Un programa debe chequear los valores de SQLCOD or
SQLSTT para determinar si la ultima sentencia SQL fue exitosa:
Si SQL encuentra un error mientras procesa la sentencia, SQLCOD tiene un valor
negativo, y los primeros dos caracteres del SQLSTT no son "00", "01",
or "02".
Si SQL encuentra una advertencia (warning) pero en una condición valida durante el
procesamiento de sentecias SQL, el SQLCOD tiene un numero positivo y los dos primeros
caracteres del SQLSTT son "01".
Si su sentencia SQL es procesada sin encontrar una condición de error o advertencia, el
SQLCOD retorna 0 y SQLSTT es "0000".
La condicion comunmente usada "No record found" (registro no encontrado)
devuelve los valores SQLCOD = +100 or SQLSTT = "02000".
El area de comunicaciones contiene muchos otros campos con información relacionada con la
sentencia SQL ejecutada.
La sentencia WHENEVER (donde quiera que)
Como alternativa de chequear los valores de SQLCOD o SQLSTT, un programador puede usar la
sentencia WHENEVER.
Esta sentencia indica al SQL chequear SQLSTT y SQLCOD, y continuar la precesamiento de su
programa o bifurcar a otra area de su programa si un error, exepcion, o advertencia existe
como resultado de la ejecuciòn de una sentencia SQL. Un manejador de condiciones de
excepción puede ser escrito por el programador para examinar los campos SQLCOD o SQLSTT
para tomar una acción especifica para la situación de error o excepción.
La sentencia WHENEVER tiene la siguiente apariencia:
C/Exec Sql
C+ WHENEVER Condition Action
C/End-Exec
Hay tres condiciones que puede especificar:
SQLWARNIN SQLCOD contiene un valor positivo diferente de 100
SQLERROR SQLCOD contiene un valor negativo (condición de error)
NOT FOUND SQLCOD = +100 o SQLSTT = '02000'
Puede especifiar la acción que quiere para cada condición
CONTINUE El programa continua con la siguiente sentencia
GO TO etiqueta El programa bifurca a la etiqueta (TAG) dentro del programa.
Usando un cursor
Al contrario de las operaciones nativas de base de datos, las cuales son orientadas a un
registro y permiten procesar unicamente un registro a la vez, las sentencias SQL son
orientadas a multiples registros y pueden manejar un grupo de registros a la vez. Por
ejemplo, con una sentencia DELETE puede borrar todos los artículos de un pedido. O, con
una sentencia UPDATE, puede actualizar todos los registros en un archivo si la condición
WHERE no es usada. Para lograr igual resultado con operaciones nativas, necesita escribir
un bucle y testear diferentes condiciones. Por lo tanto, usando sentencias SQL puede
simplificar algunas veces la lógica del programa.
De acuerdo con este comportamiento, una sentencia SELECT pone todos los registros
seleccionados en una tabla resultado. Usualmente, un programa transferira todos estos
registros desde la tabla de resultado SQL a un subfile así el usuario final puede ver
estos. Para acceder a una tabla resultado, SQL provee una tecnica llamada cursor. Este es
usado dentro de un programa SQL para mantener una posición en la tabla resultado.SQL usa
un cursor para trabajar con los renglones en la tabla resultado y hacer que esten
disponibles para el programa. Un programa puede tener varios cursores, aunque cada uno
debe tener un único nombre.
Sentencias relacionadas al uso de cursores:
DECLARE CURSOR, esta sentencia define el nombre del cursor y especifica los renglones a
ser recuperados con una sentencia SQL incrustada.
OPEN, abre el cursor para su uso dentro del programa. El cursor debe estar abierto antes
de que cualquier renglon puede ser recuperados.
FETCH, recupera renglones desde la tabla resultado o posiciona el cursor sobre otro
renglon.
CLOSE, cierra el cursor.
Los siguientes recortes de código muestran el uso de un cursor:
... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+..
C/Exec Sql
C+ DECLARE Cursor1 CURSOR FOR
C+ SELECT * FROM Pedidos
C+ ORDER BY Nroped
C+ FOR FETCH ONLY
C/End-Exec
C/Exec Sql
C+ OPEN Cursor1
C/End-Exec
C/Exec Sql
C+ FETCH Cursor1 INTO :SF1DS
C/End-Exec
C/Exec Sql
C+ CLOSE Cursor1
C/End-Exec
SQL soporta dos tipos de cursores: serial y scrollable. El tipo de cursor determina los
metodos de posicionamiento que pueden ser usados con el cursor.
Cursor serial
Un cursor serial es definido por defecto, si la palabra clave SCROLL no es usada. Con un
cursor serial, cada renglon de la tabla resultado puede ser tomado unicamente una vez por
cada OPEN del cursor. Cuando un cursor es abierto, este es posicionado antes del primer
renglon en la tabla resultado. Con cada sentencia FETCH, el cursor es movido al siguiente
renglon en la tabla resultado, el cual se vuelve el renglon actual. Si se especifican
variables de programa (con la clausula INTO en la sentencia FETCH), SQL mueve el contenido
del renglon actual a su variable de programa.
Esta secuencia es repetida cada vez que emite la sentencia FETCH, hasta el end-of-file
(fin de archivo - SQLCOD = 100) es alcanzado. Cuando alcanza el end-of-file, cierre el
cursor. Ya no puede acceder a ningun renglon de la tabla resultado despues de alcanzar el
end-of-file. Para usar otra vez el cursor, debe primero cerrarlo y entonces volver a
emitir la sentencia OPEN.
Cursor desplazable
Con un cursor desplazable (scrollable), los renglones de la tabla resultado pueden ser
tomados muchas veces. El cursor se mueve a travez de la tabla resultado en función a la
opción de posicion especificado en la sentencia FETCH. Cuando un cursor es abierto, este
se posiciona antes del primer renglon en la tabla resultado. Con una sentencia FETCH, el
cursor es posicionado sobre el renglon en la tabla resultado que se especifique por la
opciòn de posiciòn. Este renglon se vuelve el renglon actual.
Las siguientes opciones de desplazamiento, relativas a la posición actual del cursor, se
usadan para posicionar el cursor cuando emite la sentencia FETCH:
NEXT Posiciona el cursor sobre el siguiente renglon. (opcion por omisión)
PRIOR Posiciona el cursor sobre el renglon previo.
FIRST Posiciona el cursor sobre el primer renglon.
LAST Posiciona el cursor sobre el último renglon.
BEFORE Posiciona el cursor antes del primer renglon.
AFTER Posiciona el cursor despues del ultimo renglon.
CURRENT No cambia la posición del cursor.
RELATIVE n Posiciona el cursor en n renglones relativo a la posiciòn actual.
Un programa con SQL incrustado de ejemplo
H DATEDIT(*DMY/)
*----------------------------------------------------------------*
* Utilización de Trefilas *
*----------------------------------------------------------------*
* Indicadores *
*----------------------------------------------------------------*
FSP0004 IF E K DISK
FSP0005 IF E K DISK
FSPTCTR IF E DISK
FSP0208P1 O E PRINTER OFLIND(*IN75)
FSP0208FM CF E WORKSTN
F SFILE(SF1:SF1NBR)
F INFDS(CUR)
D CUR DS
D CURSOR 370 371B 0
* De trabajo
D FEISO S D
D x S 4 0
D dias S 4 0
* Registro del Cursor WSP47
D RWSP47 DS
D W47TRE 6P 0
D W47MEI 7P 2
D W47MES 7P 2
D W47CAQ 8A
D W47KIL 11P 2
*
C K005 KLIST
C KFLD SELSEC
C KFLD SELCEN
*
C MOVE UDATE FEISO
C EXTRCT FEISO:*D dias
C SUB 1 dias
C SUBDUR dias:*D FEISO
C *DMY MOVE FEISO SELFED
C MOVE UDATE SELFEH
C 1 CHAIN RGTCTR 01
C N01 MOVEL SPCEMP CTNO01
*
*----------------------------------------------------------------*
* Pantalla 1 - Visualizacion *
*----------------------------------------------------------------*
*
C P1 TAG
C EXSR VALI01
C MOVEA *IN(30) IND30 10
C IND30 IFEQ *ZEROS
C EXSR SF1FIL
C ENDIF
*
C P11 TAG
C WRITE F1
C EXFMT SFC1
* F3=Fin
C *IN03 CABEQ '1' FIN
C MOVEA '0000000000' *IN(30)
* F4=Nómina
C *IN04 IFEQ '1'
C EXSR AYUDA1
C GOTO P1
C ENDIF
* Cambios
C *IN26 CABEQ '1' P1
* F10=Imprimir
C *IN10 IFEQ '1'
C *IN51 ANDEQ '1'
C EXSR IMPRIM
C GOTO P11
C ENDIF
C GOTO P11
*
C FIN TAG
C SETON LR
*----------------------------------------------------------------*
* SF1FIL - Llena sf1 con renglones de estadística *
*----------------------------------------------------------------*
*
C SF1FIL BEGSR
C SETON 50
C WRITE SFC1
C SETOFF 5051
C CLEAR SF1NBR
C CLEAR TOTA01
* Definición y apertura de Cursor
C/Exec Sql
C+ Declare WSP47 Cursor for
C+ SELECT
C+ A.TRE121, A.MEI121, A.MES121, C.F01CAQ, SUM(A.KIL121)
C+ FROM "SP0121" A,
C+ "SP0110" B,
C+ "SP0001" C
C+ WHERE (NOT(TRE121 = 0 AND MEI121 = 0 AND MES121 = 0)
C+ AND (FEC121 >= :PFED)
C+ AND (FEC121 <= :PFEH)
C+ AND (:SELTRE = 0 OR TRE121 = :SELTRE)
C+ AND (:SELSEC = 0 OR SEC121 = :SELSEC)
C+ AND (:SELCEN = 0 OR CEN121 = :SELCEN))
C+ AND (ORD121 = ORD110)
C+ AND (ITE121 = ITE110)
C+ AND (ART110 = F01COD)
C+ GROUP BY A.TRE121, A.MEI121, A.MES121, C.F01CAQ
C+ ORDER BY A.TRE121, A.MEI121, A.MES121, C.F01CAQ
C+ For Fetch Only
C/End-Exec
C/Exec Sql
C+ Open WSP47
C/End-Exec
C DO 999999
* Obtiene un registro desde el cursor
C/Exec Sql
C+ Fetch WSP47 Into :RWSP47
C/End-Exec
C SQLSTT IFEQ '02000'
C LEAVE
C ENDIF
*
C Z-ADD W47KIL KILSF1
C ADD W47KIL TOTA01
*
C ADD 1 SF1NBR 4 0
C WRITE SF1
C SETON 51
C ENDDO
*
* Cierre del cursor
C/Exec Sql
C+ Close WSP47
C/End-Exec
*
C ENDSR
*----------------------------------------------------------------*
* VALI01 - Valida selecciones *
*----------------------------------------------------------------*
*
C VALI01 BEGSR
* Fecha desde
C *DMY TEST(D) SELFED 30
C N30*DMY MOVE SELFED FEISO
C N30*ISO MOVE FEISO PFED 8 0
* Fecha hasta
C *DMY TEST(D) SELFEH 31
C N31*DMY MOVE SELFEH FEISO
C N31*ISO MOVE FEISO PFEH 8 0
*
C CLEAR DESMAQ
* Sección
C SELSEC IFNE *ZEROS
C SELSEC CHAIN RG004 32
C N32 MOVEL F04DES DESMAQ
C ENDIF
* Centro
C SELSEC IFNE *ZEROS
C SELCEN ANDNE *ZEROS
C K005 CHAIN RG005 33
C N33 EVAL DESMAQ = %trim(DESMAQ) + '/' + F05DES
C ENDIF
C ENDSR
*----------------------------------------------------------------*
* AYUDA1 - Ayuda pantalla 1 *
*----------------------------------------------------------------*
*
C AYUDA1 BEGSR
C CURSOR DIV 256 FILA 3 0
C MVR COLU 3 0
C FILA IFEQ 3
* Sección
C COLU IFGE 10
C COLU ANDLE 12
C CALL 'SP3004'
C PARM PSEC3 3 0
C Z-ADD PSEC3 SELSEC
C ENDIF
* Centro
C COLU IFGE 14
C COLU ANDLE 16
C CALL 'SP3005'
C PARM PSEC3
C PARM PCEN3 3 0
C Z-ADD PSEC3 SELSEC
C Z-ADD PCEN3 SELCEN
C ENDIF
C ENDIF
C ENDSR
*----------------------------------------------------------------*
* IMPRIM - Imprime *
*----------------------------------------------------------------*
*
C IMPRIM BEGSR
C SETON 75
C DO 9999 x
C x CHAIN SF1 01
C 01 LEAVE
*
C 75 WRITE HEAD
C SETOFF 75
C WRITE DETAL
C ENDDO
C WRITE FINLIS
C ENDSR
Puedes ver el código en formato texto aquí
Documento cedido por Walter Nasich
17-01-2002
|