Búsquedas en tablas de COBOL

En este artículo vamos a analizar las diferentes formas que ofrece COBOL de hacer búsquedas en tablas

Recordemos que una tabla es cualquier variable definida con más de una ocurrencia o que pertenece a un grupo de nivel superior con más de una ocurrencia.

Por ejemplo, supongamos una tabla que almacene nombres de personas definida así:

01 TABLA.
   05 FILAS OCCURS 20.
      10 NOMBRE PIC X(15).
      10 APELLIDO PIC X(30).

Para buscar a una persona por apellido, podríamos emplear un bucle construido con un PERFORM VARYING. Tendríamos que definir en Working Storage una variable numérica para utilizarla como índice y un switch o indicador que permita saber si el apellido se ha encontrado no.

01 WS-IND               PIC 9(2) COMP.
01 WS-APELLIDO          PIC X(30) VALUE “GARCIA”.
01 SW-INDICADOR         PIC X    VALUE SPACES.
      88 NO-ENCONTRADO           VALUE “N”.
      88 ENCONTRADO              VALUE “S”.

SET NO-ENCONTRADO TO TRUE
PERFORM VARYING WS-IND FROM 1 BY 1 UNTIL WS-IND > 20 OR ENCONTRADO
   IF APELLIDO(IND) = WS-APELLIDO
      SET ENCONTRADO TO TRUE
   END-IF
END-PERFORM

IF NO-ENCONTRADO
   DISPLAY “Apellido no econtrado”
END-IF

El bloque de código anterior se podría simplificar con el uso de la instrucción SEARCH, que nos evita tener que declarar un índice explícitamente y resulta más legible. Tendríamos que cambiar la definición de la tabla para incluir el índice en la misma, de forma que quedara así:

01 TABLA.
   05 FILAS OCCURS 20 INDEXED BY IND.
      10 NOMBRE PIC X(15).
      10 APELLIDO PIC X(30).

Este tipo de índices asociados a la tabla tienen una representación interna especial, por lo que solo es posible modificar su valor mediante la instrucción SET. No se pueden utilizar en operaciones aritméticas ni en un DISPLAY. En una búsqueda con SEARCH solo hay que especificar el valor del índice en el que queremos que se empiece a buscar.

La búsqueda anterior quedaría de este modo con SEARCH:

SET NO-ENCONTRADO TO TRUE
SET IND TO 1
SEARCH FILAS
   AT END 
      DISPLAY “Apellido no encontrado”
   WHEN APELLIDO(IND) = WS-APELLIDO
      SET ENCONTRADO TO TRUE
END-SEARCH

La condición lógica del WHEN se irá evaluando para todos los elementos de la tabla hasta que sea verdadera o se llegue al final. Si se ha llegado al último elemento sin cumplirse la condición, se ejecutará la instrucción indicada en el AT END.

Como hemos comentado, las búsquedas anteriores implican recorrer todos los elementos de la tabla hasta encontrar el buscado. Existe una forma más eficiente de buscar en tablas llamada búsqueda binaria (instrucción SEARCH ALL), que utiliza un algoritmo especial. Su inconveniente es que requiere que la tabla esté ordenada por un campo clave. Además, los elementos vacíos deben contener HIGH-VALUES si el orden es ascendente o LOW-VALUES si es descendente. Si no se cumplen estos requisitos, la búsuqeda devolverá resultados incorrectos.

Para poder utilizar la búsqueda binaria, habría que modificar la definición de la tabla para añadir el campo clave:

01 TABLA.
   05 FILAS OCCURS 20 
              ASCENDING KEY IS APELLIDO 
              INDEXED BY IND.
      10 NOMBRE PIC X(15).
      10 APELLIDO PIC X(30).

Hemos indicado orden ascendente. Para orden descendente se utilizaría DESCENDING KEY IS.

En el código de la búsqueda habría que cambiar SEARCH por SEARCH ALL y se puede quitar la inicialización del índice porque se hace automáticamente.

SET NO-ENCONTRADO TO TRUE
SEARCH ALL FILAS
   AT END 
      DISPLAY “Apellido no encontrado”
   WHEN APELLIDO(IND) = WS-APELLIDO
      SET ENCONTRADO TO TRUE   
END-SEARCH

 

Más de un registro de salida por cada registro de entrada en un Sort

En la definición de los registros de salida de un sort con BUILD se puede incluir una barra (carácter “/”) para insertar un registro en blanco. Los campos y/o literales que se incluyan a continuación formarán parte del nuevo registro.

Por defecto se inserta un único registro. Si añadimos un número delante de la barra, se insertarán n registros en blanco.

Este separador solo puede incluirse dentro de un BUILD o OUTREC que forme parte de un OUTFIL.

Ejemplo:

//PASSORT EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=FICH.ENTRADA,DISP=SHR
//
//SALIDA1 DD DSN=FICH.SALIDA1,
// DISP=(,CATLG,DELETE),
// SPACE=(TRK,(10,10),RLSE),
// RECFM=FB
//SALIDA2 DD DSN=FICH.SALIDA2,
// DISP=(,CATLG,DELETE),
// SPACE=(TRK,(10,10),RLSE),
// RECFM=FB
//SYSIN DD *
SORT FIELDS=COPY
OUTFIL FNAMES=SALIDA1,BUILD=(1,10,/,11,10)
OUTFIL FNAMES=SALIDA2,BUILD=(1,10,11,10,2/)

En SALIDA1, por cada registro del fichero de entrada generamos dos registros en el fichero de salida con campos de entrada diferentes.

En SALIDA 2, por cada registro del fichero de entrada generamos un registro con campos del fichero de entrada y dos registros en blanco.


FETCH FIRST n ROWS ONLY y OPTIMIZE FOR n ROWS

Las cláusulas OPTIMIZE FOR n ROWS y FETCH FIRST n ROWS ONLY de DB2 permiten optimizar una SELECT indicándole al DB2 el número de filas (n) que estimamos se van a obtener. La diferencia entre ambas es que con OPTIMIZE FOR se recuperan todas las filas que cumplan la condición de la SELECT y con FETCH FIRST sólo las n primeras.

IBM recomienda utilizar OPTIMIZE for 1 ROW siempre que se vaya recuperar un número reducido de filas (aunque sea superior a uno). De esta forma le indicamos a DB2 que intente evitar caminos de acceso que impliquen ordenaciones.

Ejemplo:

SELECT CAMPO1,
       CAMPO2,
       CAMPO3
FROM TABLA
WHERE CAMPO4  = :VARIABLE
FETCH FIRST 10 ROWS ONLY

Esta SELECT recuperará un máximo de 10 filas. Un intento de recuperar la número 11 devolverá un SQLCODE 100.

El FETCH FIRST implica también optimizar el camino de acceso para el mismo número de filas. Es decir, en el ejemplo anterior se asume por omisión un OPTIMIZE FOR 10 ROWS.

Cuando queramos hacer una optimización para un número inferior de filas, debemos indicarlo explícitamente. Por ejemplo, para optimizar la SELECT anterior siguiendo la recomendación de IBM:

SELECT CAMPO1,
       CAMPO2,
       CAMPO3
FROM TABLA
WHERE CAMPO4  = :VARIABLE
FETCH FIRST 10 ROWS ONLY
OPTIMIZE FOR 1 ROW

Cuando solo queramos optimizar la SELECT sin limitar el número de filas, basta con incluir el OPTIMIZE:

SELECT CAMPO1,
FROM TABLA
WHERE CAMPO2  = :VARIABLE
OPTIMIZE FOR 1 ROW

<

Crear informes con un Sort

En este artículo vamos a introducir las sentencias de control del parámetro OUTFIL del Sort que permiten generar un fichero de salida con formato de informe. Las principales son:

HEADER1
Cabecera general del informe.

HEADER2
Cabecera de página.

HEADER3
Cabecera de sección.

TRAILER1
Pie final del informe

TRAILER2
Pie de página.

TRAILER3
Pie de sección.

SECTIONS
Campo/s de ruptura que marcan el final de una sección y el inicio de la siguiente.

Su sintaxis completa se puede encontrar en el manual de IBM. Aquí vamos a aprender a utilizarlas mediante un sencillo ejemplo.

Partimos de un fichero con las ventas que han realizado los comerciales de una empresa. Tiene la siguiente estructura:

Campo Formato COBOL
COMERCIAL PIC X(25)
SUCURSAL PIC X(10)
TOTAL VENDIDO PIC 9(9)V9(2) COMP-3
COMISIONES PIC 9(9)V9(2) COMP-3

Y queremos obtener un informe que muestre las ventas y comisiones de cada vendedor, así como los totales de cada sucursal. Tendrá cabeceras de página y de sección (sucursal) y pies de sección.


                                              23/04/2014  PAG.     1
         INFORME DE VENTAS Y COMISIONES POR SUCURSAL
         -------------------------------------------
SUCURSAL: BARCELONA

NOMBRE                     SUCURSAL    VENTA         COMISION
------------------------   ----------  ------------  ------------
NOMBRE APELL1 APELL2       BARCELONA        4108,92        350,65
NOMBRE APELL1 APELL2       BARCELONA       12789,23       1190,67
NOMBRE APELL1 APELL2       BARCELONA        2109,34        208,65
-----------------------------------------------------------------------
TOTAL BARCELONA                            19007,49       1749,97

SUCURSAL: LEVANTE

NOMBRE                     SUCURSAL    VENTA         COMISION
------------------------   ----------  ------------  ------------
NOMBRE APELL1 APELL2      LEVANTE          8177,01         711,23
…                        …                  …            …
 
TOTAL LEVANTE                               39022,42       3749,92
…
 
                                                 23/04/2014  PAG.     2
            INFORME DE VENTAS Y COMISIONES POR SUCURSAL
            -------------------------------------------
…

Para generarlo utilizaríamos el siguiente paso de Sort:

//PA0010   EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=FICHERO.ENTRADA,
//         DISP=SHR
//SALIDA   DD DSN=FICHERO.SALIDA,
//         DISP=(NEW,CATLG,DELETE),RECFM=FB,DSORG=PS,LRECL=72
//SYSIN    DD *
SORT FIELDS=(26,10,CH,A)
OUTFIL FNAMES=SALIDA,
BUILD=(1X,1,25,2X,26,10,2X,36,6,PD,EDIT=(IIIIIIITT,TT),
2X,42,6,PD,EDIT=(IIIIIIITT,TT),6X),
REMOVECC,
HEADER2=(50X,DATE=(DM4/),2X,'PAG.',PAGE,/,
10X,'INFORME DE VENTAS Y COMISIONES POR SUCURSAL',/,
10X,'-------------------------------------------'),
SECTIONS=(26,10,
HEADER3=(/,2:'SUCURSAL: ',26,10,/,
/,2:'NOMBRE',29:'SUCURSAL',41:'VENTA',
55:'COMISION',/,
2:'------------------------',
29:'----------',
41:'------------',
55:'------------'),
TRAILER3=(2:71'-',/,1X,'TOTAL ',26,10,23X,
TOTAL=(36,6,PD,EDIT=(IIIIIIITT,TT)),
2X,
TOTAL=(42,6,PD,EDIT=(IIIIIIITT,TT))))

Vemos que se ordena por el campo de ruptura (sucursal, posición 26). A continuación se incluye la ficha OUTFIL correspondiente al fichero de salida. Dentro de ella incluimos el parámetro BUILD para generar los registros de detalle y a continuación, los parámetros que definen el informe. Algunos de ellos ya los hemos descrito en la introducción; los nuevos que aparecen en el ejemplo son:

REMOVECC
Elimina los caracteres de control que se incluyen por defecto

TOTAL
Parámetro que se puede incluir dentro de cualquiera de los pies del informe (TRAILER1, TRAILER2 y TRAILER3). Muestra la suma de todos los valores del campo indicado. En la suma se incluirán todos los registros del informe, pagina o sección, dependiendo del pie en el que se sitúe.

Comprobar si un fichero está vacío con un Sort

En un Sort es posible forzar un código de retorno determinado (0, 4 u 8) si el SORTOUT (fichero de salida) no tiene registros. Se hace mediante la opción NULLOUT = RCn, donde n puede tomar el valor 0, 4 u 8 (el valor por defecto es 0).
Gracias a esta utilidad podemos construir un paso de JCL que devuelva retorno 4 si el fichero de entrada está vacío y 0 en caso contrario. Como solo necesitamos leer un registro del fichero de entrada, usamos también la instrucción STOPAFT = 1.

Ejemplo:


//PA0010 EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=FICHERO.PRUEBA.NULLOUT,DISP=SHR
//SORTOUT DD DSN=&&TEMP,DISP=(,PASS)
//SYSIN DD *
OPTION COPY,NULLOUT=RC4,STOPAFT=1

Controlar la existencia de un fichero en un JCL

La existencia de un fichero se puede controlar mediante el comando LISTCAT de la utilidad IDCAMS. Esta devolverá código de retorno 4 si el fichero que se le pasa como parámetro no existe en el catálogo.

Ejemplo:

Tenemos un JOB que recibe un fichero de entrada. En caso de que dicho fichero no exista, queremos que el JOB no haga nada pero termine sin JCL Error.

//PA0010   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  LISTCAT ENTRIES (FIC.ENTRAD.EJEMPLO) ALL   
/*
//IFPAS1  IF  PA0010.RC EQ 0 THEN
//PA0020   …
//PA0030   …
//…
//ENPAS1 ENDIF

Recordemos que IDCAMS nos permite cambiar el código de retorno de la ejecución. Por ejemplo, si nos interesa que el job termine con retorno 1 en vez de 4, podemos forzarlo así:

LISTCAT ENTRIES (FIC.ENTRAD.EJEMPLO) ALL
  IF LASTCC NE 0 THEN DO
    SET MAXCC=1
  END

Cálculos con fechas en COBOL


El COBOL de IBM para z/OS incluye dos funciones que simplifican mucho los cálculos con fechas, gracias a que convierten una fecha en formato AAAAMMDD en su equivalente numérico y a la inversa. Ello nos permite hacer sumas o restas con fechas fácilmente, sin necesidad de tener en cuenta el número de días de cada mes o si alguno de los años que intervienen en el cálculo es bisiesto.

Las funciones son:

INTEGER-OF-DATE (argumento)

El argumento debe ser un número entero que represente una fecha en formato AAAAMMDD comprendida entre 16010101 y 99991231.

El resultado es un número entero en el rango de 1 a 3.067.671 que representa el número de días transcurridos entre el 31 de diciembre de 1600 y la fecha del argumento.

DATE-OF-INTEGER (argumento)

El argumento debe ser un número entero comprendido entre 1 y 3.067.671 que represente el número de días transcurridos desde el 31 de diciembre de 1600.

El resultado es la fecha en formato AAAAMMDD equivalente al número entero pasado como argumento.

Ejemplos:

Definimos las  variables

01  W-FECHA1            PIC 9(08).
01  W-FECHA2            PIC 9(08).
01  W-DIAS              PIC 9(04).

1)  Calcular el número días de diferencia entre el 5 de marzo de 2012 y el 10 de febrero de 2011.

MOVE  20120305  TO W-FECHA2
MOVE  20110210  TO W-FECHA1

COMPUTE W-DIAS =
FUNCTION INTEGER-OF-DATE(W-FECHA2) -
FUNCTION INTEGER-OF-DATE(W-FECHA1)

2) Restarle diez días al 7 de marzo de 2013.

MOVE 20130307 TO W-FECHA1

COMPUTE W-FECHA2 =
FUNCTION DATE-OF-INTEGER (
FUNCTION INTEGER-OF-DATE(W-FECHA1) - 10 )




Conversión de fichero de longitud variable a fija y viceversa

La conversión de un fichero de longitud variable a fija y viceversa en un Sort se hace mediante las opciones VTOF y FTOV del parámetro OUTFIL del Sort.

Recordemos que el parámetro OUTFIL permite generar de 1 a n ficheros de salida. Cada uno de estos puede ser construido de forma independiente mediante instrucciones BUILD o OUTREC y condiciones INCLUDE u OMIT.

Conversión de variable a fija

La opción VTOF (o su sinónimo CONVERT) incluida en un grupo OUTFIL indica que los registros de entrada de longitud variable deben ser convertidos a longitud fija.

Se debe incluir también un parámetro BUILD o OUTREC, que generará un registro reformateado de longitud fija sin el descriptor de registro de 4 bytes (los datos comenzarán en la posición 1).

Los campos que se incluyan en el parámetro BUILD o OUTREC deberán estar referidos a los registros de entrada de longitud variable (los datos empiezan en la posición 5).

VTOF utiliza por defecto la opción VLFILL=X’40’ (relleno con espacios) para que sea posible procesar registros de entrada de longitud variable que sean demasiado cortos para contener todos los campos especificados en BUILD o OUTREC.

El formato de registro del fichero de salida será FB por defecto. Y si se especifica, deberá ser FB u otro de los de longitud fija

Si se utiliza VTOF con FTOV, IFTRAIL, IFTHEN, FINDREP u OVERLAY, el Sort terminará con error.

Ejemplo:

//SORT006  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=ENTRADA...,
//         DISP=SHR
//SALIDA1  DD DSN=SALIDA...,
//         DCB=(RECFM=FB,LRECL=300,BLKSIZE=0,DSORG=PS),
//         DISP=(,CATLG,DELETE),
//         SPACE=(TRK,(2,1),RLSE)
//SYSIN    DD *
SORT     FIELDS=COPY
OUTFIL   FNAMES=SALIDA1,VTOF,BUILD=(5,300)
/*

* En vez de VTOF podemos usar su sinónimo CONVERT:

OUTFIL   FNAMES=SALIDA1,CONVERT,BUILD=(5,300)

Conversión de fija a variable

FTOV incluida en un grupo OUTFIL indica que los registros de entrada de longitud fija deben ser convertidos a longitud variable.

Si no se incluye un parametro OUTREC, BUILD, OVERLAY, FINDREP o IFTHEN, los registros de entrada de longitud fija completos se transforma en registros de salida de longitud variable

Si se incluye un parametro OUTREC, BUILD, OVERLAY, FINDREP o IFTHEN, los campos especificados se transforman en registros de salida de longitud variable.

En los dos casos, antes de escribir los registros de salida se les añade un descriptor de registro de 4 bytes (los datos empiezan en la posición 5).

Los campos especificados en OUTREC, BUILD, OVERLAY, FINDREP o IFTHEN deberán estar referidos a los registros de entrada de longitud fija (los datos empiezan en la posición 1).

El formato de registro del fichero de salida del OUTFIL será VB por defecto. Y si se especifica, deberá ser FB o cualquier otro de longitud variable.

Si no se especifica el parámetro LRECL para el fichero de salida, se le dará una longitud que permita contener el registro de mayor longitud.

Ejemplo:

EXEC  PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DISP=SHR,DSN=ENTRADA…
//SALIDA   DD DSN=SALIDA…
//          DISP=(NEW,CATLG,DELETE),
//          LRECL=448,RECFM=VB,DSORG=PS
//SYSIN    DD *
OPTION COPY
OUTFIL FNAMES=SALIDA,FTOV,OUTREC=(1:1,444)
/*

Fuente: DFSORT Application Programming Guide v1R13

Introducción al parámetro DISP de la DD de los JCL

DISP es un parámetro de la instrucción DD (Data Definition) de los JCL. Sirve para indicarle al sistema el estado actual de un fichero y las acciones a realizar sobre el mismo si el paso termina correctamente y en caso de terminación anormal (abend).  Su formato es:

DISP=(Estado, Acción normal, Acción anormal).

Valores para el subparámetro de estado

NEW

Crear nuevo dataset

OLD

El dataset ya existe y se require uso exclusivo (no compartido) del mismo.

SHR

El dataset ya existe y no se require su uso exclusivo. Otros jobs pueden utilizarlo al mismo tiempo.

MOD:

Si el dataset ya existe, indica que se quieren añadir registros al final del mismo (debe ser secuencial). Si el dataset no existe, indica que debe ser creado.

Valores para el subparámetro de acción normal

DELETE

Indica que el dataset dejará de ser necesario. Dependiendo de la configuración de seguridad y de si está almacenado en cinta o no, puede suponer que se eliminará físicamente o bien que su espacio quedará disponible para otros datasets.

KEEP

Mantener el dataset en el volumen en el que esté almacenado.

PASS

Pasar el dataset para su utilización en un paso posterior del job. Ahorra tiempo con respecto a KEEP, ya que el sistema retiene información sobre la ubicación y el volumen. De todas formas, es preferible evitar su su uso porque puede provocar pérdida de datos o incluso el borrado del fichero si no se codifica correctamente en ciertos casos.

CATLG

Incluir una entrada que apunte al dataset en el catálogo, lo que nos permitirá utilizar el dataset posteriormente.

UNCATLG

Si está activado el sistema de gestión automática de almacenamiento (SMS), que suele ser lo habitual, es ignorado y equivale a KEEP. Indica que se eliminará del catálogo la entrada correspondiente al dataset.

Valores para el subparámetro de acción anormal

DELETE

Liberar el espacio que ocupa el dataset, que quedará disponible para su uso por otros datasets.

KEEP

Mantener el dataset.

CATLG

Incluir una entrada que apunte al dataset en el catálogo, lo que nos permitirá utilizar el dataset posteriormente.

UNCATLG

Si está activado el sistema de gestión automática de almacenamiento (SMS), que suele ser lo habitual, es ignorado y equivale a KEEP. Indica que se eliminará del catálogo la entrada correspondiente al dataset.

Valores por defecto

Si se omite el suparámetro de estado, el valor por defecto es NEW.

Si se omite el subparámetro de ejecución normal, el valor por defecto es DELETE para un dataset nuevo y KEEP para un dataset existente.

Si se omite el suparámetro de ejecución anormal, el valor por defecto es el especificado para la ejecución normal, salvo que se trate de PASS. En ese caso el valor por defecto es DELETE para un dataset nuevo o KEEP para uno existente.

Para indicar la ausencia del primer y el segundo subparámetro se debe incluir la coma de separación.

Ejemplos:

DISP=(,CATLG,DELETE) – Equivale a DISP=(NEW,CATLG,DELETE)

DISP=(,KEEP) – Equivale a (NEW,KEEP,KEEP)

DISP=(OLD,,DELETE) – Equivale a (OLD,KEEP,DELETE)

Si se omite el parámetro DISP por completo, el valor por defecto es  (NEW,DELETE,DELETE) Es decir, un fichero que se crea y se borra en el mismo paso.

Nota:  Utilizamos el término inglés dataset para referirnos a los ficheros que se utilizan en el z/OS. Se trata de conjuntos de datos organizados en forma de registros y bloques que pueden ser almacenados en dispositivos de acceso directo (DASD) o en cinta.

Descarga de una tabla con DSNTIAUL

La utilidad DB2 DSNTIAUL permite realizar una descarga de tabla a fichero fácilmente. Tiene menos restricciones de seguridad que la utilidad UNLOAD, por lo que es ideal para hacer descargas en entornos DB2 de prueba.

En su forma más sencilla se ejecutaría con un JCL como el siguiente:

//DESCARGA EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB DD DSN=PRE.SDSNLOAD,DISP=SHR
//           DSN=PRE.RUNLIB.LOAD,DISP=SHR
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(SUB)
RUN PROGRAM(DSNTIAUL) PLAN(DSNTIAUL) -
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSREC00 DD DSN=FIC.SYSREC00,DISP=(,CATLG,DELETE)
//SYSPUNCH DD DSN=FIC.SYSPUNCH,DISP=(,CATLG,DELETE)
//SYSIN DD *
CREADOR.TABLA

Observaciones:

  1. En la STEPLIB hemos incluido dos librerías de cargables (sustituir “PRE” por el prefijo que corresponda al subsistema DB2 al que queramos acceder)
    – DB2.SDSNLOAD:  contiene el cargable del procesador de comandos DSN
    – DB2.RUNLIB.LOAD:  contiene el cargable de DSNTIAUL
  2. En la SYSTSIN indicamos el nombre del subsistema DB2 (sustituir “SUB” por el nombre del subsistema),  la utilidad (DSNTIAUL) y el nombre del plan, que no siempre coincide con el de la utilidad. Tendremos que consultar el nombre que tenga  en nuestra instalación.
  3. En la SYSIN se especifica el nombre de la tabla. También es posible incluir un WHERE y un ORDER BY (en realidad es una sentencia SQL sin el “SELECT * FROM”)
  4. Ficheros de salida:
    – SYSREC00: Registros descargados de la tabla
    – SYSPUNCH: Contiene las sentencias de control para hacer una carga de la tabla mediante la utilidad LOAD.

El siguiente ejemplo nos va a servir para introducir nuevas opciones de esta utilidad.

//DESCARGA EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB DD DSN=PRE.SDSNLOAD,DISP=SHR
//           DSN=PRE.RUNLIB.LOAD,DISP=SHR
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(SUB)
RUN PROGRAM(DSNTIAUL) PLAN(DSNTIAUL) PARMS('SQL,1000')
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSREC00 DD DSN=FIC.SYSREC00,DISP=(,CATLG,DELETE)
//SYSREC01 DD DSN=FIC.SYSREC01,DISP=(,CATLG,DELETE)
//SYSPUNCH DD DSN=FIC.SYSPUNCH,DISP=(,CATLG,DELETE)
//SYSIN DD *
SELECT CREADOR.TABLA1_CAMPO1, CAST(COUNT(*) AS CHAR(10)) FROM CREADOR.TABLA1
GROUP BY CAMPO1;
SELECT * FROM CREADOR.TABLA2 ORDER BY CAMPO1, CAMPO2;

Hemos incluido los parámetros ‘SQL’, que nos permite incluir sentencias SQL completas en la SYSIN; y 1000 para limitar el número de filas de salida a ese valor.

Al haber dos sentencias SQL, se generan dos ficheros de salida (SYSREC00 y SYSREC01). Es posible incluir hasta 99 sentencias SQL separadas por puntos y coma que darían lugar a 99 ficheros de salida.