lunes, 12 de septiembre de 2011

Ejemplo 5: programa con DB2

En este ejemplo vamos a ver un programa que accede a base de datos para recuperar información. Veremos un ejemplo sencillo en el que el programa recuperará de SYSIN la clave por la que accederá a la base de datos, y displayará la información recuperada por SYSOUT.

JCL:

//PASO01 EXEC PGM=IKJEFT01,DYNAMNBR=20
//SYSTSIN DD *
DSN SYSTEM(DSN1)
RUN PROGRAM(PRUEBA5) PLAN(PRUEBA5) -
LIB('LIBRERIA.DE.TU.INSTALACION')
//SYSOUT DD SYSOUT=*
//SYSIN DD *
PEREZ
/*


Donde EXEC PGM=IKJEFT01 ejecutará el programa que le indiquemos en el SYSTSIN.
El DSN SYSTEM dependerá de cada instalación y puede variar según el entorno (desarrollo, preproduccion, explotación...).
En PROGRAM indicaremos el programa con DB2 a ejecutar, y en PLAN el plan DB2 asociado.
La librería indicada en LIB es opcional.
En la SYSIN le pasaremos la clave por la que accederemos a la tabla. En este caso será el campo APELLIDO.

TABLA:

Nombre     Apellido   Telefono
CARMEN     PEREZ      666555444
JAVIER     LOPEZ      666999888
SARA       GARCIA     666222111


Donde:
El campo Nombre es un CHAR(10).
El campo Apellido es un CHAR(10).
El campo Telefono es un DECIMAL(9).

PROGRAMA:

 IDENTIFICATION DIVISION.
 PROGRAM-ID. PRUEBA5.
*==========================================================*
*     PROGRAMA QUE ACCEDE A BASE DE DATOS CON UNA SELECT
*==========================================================*
*
 ENVIRONMENT DIVISION.
*
 CONFIGURATION SECTION.
*
 SPECIAL-NAMES.
     DECIMAL-POINT IS COMMA.
*
 DATA DIVISION.
*
 WORKING-STORAGE SECTION.
*

 EXEC SQL
    INCLUDE SQLCA
 END-EXEC.

 EXEC SQL
    INCLUDE TABLA
 END-EXEC.

 01 WX-SYSIN.
    05 WX-CLAVE        PIC X(10).
    05 FILLER          PIC X(70).

 01 WX-TABLA.
    05 WX-NOMBRE       PIC X(10).
    05 WX-APELLIDO     PIC X(10).
    05 WX-TELEFONO     PIC S9(9) COMP-3.
 01 WX-VARIABLES.
    05 WX-TELEFONO-NUM PIC 9(9).
*
************************************************************
 PROCEDURE DIVISION.
************************************************************
*  |     00000 - PRINCIPAL
*--|------------------+----------><----------+-------------*
* 1| EJECUTA EL INICIO DEL PROGRAMA
* 2| EJECUTA EL PROCESO DEL PROGRAMA
* 3| EJECUTA EL FINAL DEL PROGRAMA
************************************************************
 00000-PRINCIPAL.
*
     PERFORM 10000-INICIO
*
     PERFORM 20000-PROCESO
*
     PERFORM 30000-FINAL
     .
************************************************************
*  |     10000 - INICIO
*--|------------+----------><----------+-------------------*
*  | SE REALIZA EL TRATAMIENTO DE INICIO:
* 1| Inicialización de Áreas de Trabajo
* 2| Lectura de SYSIN
************************************************************
 10000-INICIO.
*
     INITIALIZE WX-SYSIN

                WX-TABLA
                WX-VARIABLES

     ACCEPT WX-SYSIN FROM SYSIN

     .
************************************************************
*  |     20000 - PROCESO
*--|------------------+----------><------------------------*
*  | SE REALIZA EL TRATAMIENTO DE LOS DATOS:
* 1| Realiza el acceso a base de datos
************************************************************
 20000-PROCESO.
*

     EXEC SQL
        SELECT NOMBRE
              ,TELEFONO
          INTO :WX-NOMBRE
              ,:WX-TELEFONO 
          FROM TABLA
         WHERE APELLIDO = :WX-CLAVE
         ORDER BY APELLIDO
     END-EXEC

     EVALUATE TRUE
        WHEN SQLCODE EQUAL ZEROES
             DISPLAY 'TODO VA BIEN'

             PERFORM 21000-GRABAR-SALIDA

        WHEN SQLCODE EQUAL +100
             DISPLAY 'NO ENCONTRE NADA'


        WHEN OTHER
             DISPLAY 'ALGO HA IDO MAL. EL SQLCODE ES: 'SQLCODE
             PERFORM 30000-FINAL
     END-EVALUATE
    

     .

*************************************************************
*  |     21000 - GRABAR - SALIDA
*--|------------------+----------><----------+--------------*
*  | ESCRIBE EN SYSOUT LA INFORMACIÓN RECUPERADA DE LA TABLA
*************************************************************
  21000-GRABAR-SALIDA.
*

     MOVE WX-TELEFONO TO WX-TELEFONO-NUM
     MOVE WX-CLAVE    TO WX-APELLIDO

     DISPLAY 'NOMBRE  :'WX-NOMBRE

     DISPLAY 'APELLIDO:'WX-APELLIDO
     DISPLAY 'TELEFONO:'WX-TELEFONO-NUM

     .

************************************************************
*  |     30000 - FINAL
*--|------------------+----------><----------+-------------*
*  | FINALIZA LA EJECUCION DEL PROGRAMA
************************************************************
 30000-FINAL.
*
     STOP RUN
     .


En el programa podemos ver las siguientes divisiones/secciones:
IDENTIFICATION DIVISION: existirá siempre.
ENVIRONMENT DIVISION: existirá siempre.
CONFIGURATION SECTION: existirá siempre.
En este caso no existirá la INPUT-OUTPUT SECTION, pues nuestro programa no utiliza ficheros.
DATA DIVISION: existirá siempre.
En este caso no existirá la FILE SECTION, pues nuestro programa no utiliza ficheros.
WORKING-STORAGE SECTION: exisitirá siempre.
En este caso no exisistirá la LINKAGE SECTION pues el programa no se comunica con otros programas.
PROCEDURE DIVISION: exisitirá siempre.


En el programa podemos ver las siguientes sentencias:
PERFORM: llamada a párrafo
INITIALIZE: para inicializar variable
ACCEPT: esta sentencia recoge la información del campo indicado en el "FROM". En este caso recoge la información almacenada en "SYSIN"; la que nosotros hemos introducido en el JCL.
EXEC SQL/END-EXEC: son las etiquetas para incluir código SQL. Todas las sentencias DB2 se deben incluir entre estas etiquetas.
EVALUATE TRUE: Valida que se cumplan las condiciones indicadas en cada uno de los "WHEN".
MOVE/TO: movemos la información de un campo a otro
DISPLAY: escribe el contenido del campo indicado en la SYSOUT del JCL.
STOP RUN: sentencia de finalización de ejecución.


Descripción del programa:
En la WORKING-STORAGE hemos incluido la copy SQLCA (SQL communications area ó área de comunicación SQL), que es la que utiliza el gestor de base de datos para devolver la información de errores. La estructura es la siguiente:

01 SQLCA SYNC.
   05 SQLCAID PIC X(8) VALUE "SQLCA ".
   05 SQLCABC PIC S9(9) COMP-5 VALUE 136.
   05 SQLCODE PIC S9(9) COMP-5.
   05 SQLERRM.
   05 SQLERRP PIC X(8).
   05 SQLERRD OCCURS 6 TIMES PIC S9(9) COMP-5.
   05 SQLWARN.
      10 SQLWARN0 PIC X.
      10 SQLWARN1 PIC X.
      10 SQLWARN2 PIC X.
      10 SQLWARN3 PIC X.
      10 SQLWARN4 PIC X.
      10 SQLWARN5 PIC X.
      10 SQLWARN6 PIC X.
      10 SQLWARN7 PIC X.
      10 SQLWARN8 PIC X.
      10 SQLWARN9 PIC X.
      10 SQLWARNA PIC X.
   05 SQLSTATE PIC X(5).
*


Como veis incluye la variable SQLCODE, donde guardará el código de retorno que nos indicará si la consulta ha ido bien o no.
Hemos incluido también la DCLGEN de la tabla "TABLA" que contendrá los campos DB2 de la tabla (los que codificamos en la parte de la SELECT) y sus campos working y que tendrá algo de este estilo:

EXEC SQL  DECLARE TABLA TABLE
     (NOMBRE        CHAR(10)           NOT NULL,
      APELLIDO      CHAR(10)           NOT NULL,
      TELEFONO      DECIMAL(9)         NOT NULL)
END-EXEC.

01  DCLTABLA.
     10 TAB-NOMBRE        PIC X(10).
     10 TAB-APELLIDO      PIC X(10).
     10 TAB-TELEFONO      PIC S9(9) COMP-3.

En el párrafo de inicio, inicializamos todas las variables de trabajo definidas en la WORKING-STORAGE, y realizamos un ACCEPT para recoger la información que hemos puesto en la SYSIN. En nuestro caso se trata del campo clave por el que accederemos a nuestra tabla.

En el párrafo de proceso, hacemos una SELECT a la tabla con la condición APELLIDO = :WX-CLAVE. Donde WX-CLAVE contiene el apellido recogido por SYSIN. Comprobamos el SQLCODE que nos devuelve esta consulta:
Si el SQLCODE es cero, la consulta ha ido bien y se ha encontrado el apellido contenido en WX-CLAVE en nuestra tabla. En nuestro caso dará este SQLCODE, pues "PEREZ" está en la tabla.
Si el SQLCODE es 100, la consulta ha ido bien pero no ha encontrado el apellido "PEREZ" en nuestra tabla.
Si el SQLCODE es cualquier otro, la consulta ha ido mal y habrá que comprobar en la tabla de errores DB2 cuál ha sido el problema.

NOTA: el tema de la puntuación en sentencias SQL (es decir, poner o no poner un punto '.' al final de una sentencia DB2 dentro de la PROCEDURE DIVISION) dependerá de la versión del compilador.

En el párrafo de GRABAR-SALIDA, movemos el campo WX-TELEFONO a una variable numérica sin comprimir (WX-TELEFONO-NUM), para que al hacer el DISPLAY se vea correctamente. Luego displayamos los campos recuperados de la consulta.


RESULTADO:

NOMBRE  : CARMEN
APELLIDO: PEREZ
TELEFONO: 666555444


Si queréis probar este ejemplo, tendréis que hacer una sentencia SELECT a una tabla que exista en vuestra base de datos^^

10 comentarios:

Anónimo dijo...

muy util!!!!!!!!!!! :D

Tallian dijo...

Me alegro de que te haya servido : )
Gracias por leernos!

Anónimo dijo...

Hola Tallian me gusta mucho tu trabajo es mas lo estoy siguiendo y me parece muy útil yo que soy novato en COBOL me es fantástico , pero tengo un par de dudas hasta ahora.. sobre el job de este programa
* cuando escribes DSN1 ?? a que te refieres es un origen de datos?? o que es ()
DSN SYSTEM(DSN1)
*que significa esto es un archivo de un DataSet ?? o una librería externa?? por cierto leí que es opcional pero me gustaría sacarme la duda. y si esto influye mucho en la ejecución del programa
LIB('LIBRERIA.DE.TU.INSTALACION')

por lo demás si entendí y esta muy bueno.. espero me respondas :D y si pudieras publicar algunos ejemplos en el IDE Mainframe Express 2.5 que es el que uso pues , apenas estoy aprendiendo y eso es a la mala y la info que hay en la web sobre este IDE o al menos los ejemplos están en pedazos y pedazos y no explican el procedimiento completo.. espero me puedas ayudar.. gracias de antenmano

Tallian dijo...

Hola y perdón por tardar tanto en responder.
El DSN SYSTEM depende de la instalación, si buscas algún otro JOB en las librerías con las que trabajes que ejecute un programa con DB2 tendrás el tuyo. Se refiere al entorno en el que estás trabajando (desarrollo, preproducción, producción).
La LIB efectivamente es opcional.

Me temo que con tu IDE no tengo experiencia. Por lo que he visto es el de Microfocus. Yo siempre he trabajado con IBM...

Suerte!!

Tallian dijo...

Acabo de añadir la include de la tabla... Que desastre!!!

Anónimo dijo...

Hola , primero felicitarte por la página y segundo quería realizar una pequeña correción.
El programa estaría ya perfecto , si no recuperara en el SELECT el campo apellido, ya que ya esta como clave y lo tenemos en el WHERE.-

Loboc dijo...

Correcta matización. Cualquier campo que se ponga por igualdad en el WHERE (se conoce su valor previo consulta) no debe ser recuperado en el SELECT para mejorar el rendimiento del acceso DB2.

Anónimo dijo...

Hola Coboleros... hemos desarrollado un aplicativo del mapa de hambre en cobol wow, ahora queremos llevarloa a android... es posible ? me responden por favor a fundacion@mapadehambre.com gracias y un abrazo

jesus castro dijo...

en una variable dice relefono en ves de teléfono... pero toda la información y explicación excelente !!!

Tallian dijo...

jijiji, no lo había visto :P