lunes, 30 de abril de 2012

JCL: Obtener un fichero más pequeño mediante SORT

     Para obtener un fichero más pequeño mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                     DISP=(,CATLG,DELETE),
          //                     SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY
              OUTREC FIELDS=(1,30)

     Obsérvese que para generar un fichero más pequeño se utiliza lo siguiente OUTREC FIELDS=(1,30) => esto supone que nos vamos a quedar con las primeras 30 posiciones del fichero de entrada y dichas posiciones serán las que se guarden en el fichero FICH.PRUEBA.SALIDA (importante: el valor que aparece en la segunda posición del OUTREC debe coincidir con la longitud del fichero resultante).

jueves, 19 de abril de 2012

JCL: Obtener dos ficheros mediante SORT

     Para obtener dos ficheros en los que cada uno de ellos tengamos registros distintos mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN   DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SALIDA1  DD DSN=FICH.PRUEBA.SALID1,
          //                    DISP=(,CATLG,DELETE),
          //                    SPACE=(CYL,1,1)
          //SALIDA2  DD DSN=FICH.PRUEBA.SALID2,
          //                    DISP=(,CATLG,DELETE),
          //                    SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY
              OUTFIL FNAMES=SALIDA1,INCLUDE=(18,2,CH,EQ,C'XX')
              OUTFIL FNAMES=SALIDA2,INCLUDE=(18,2,CH,EQ,C'XY')

     Obsérvese que para generar dos ficheros, FICH.PRUEBA.SALID1 y FICH.PRUEBA.SALID2, en los que uno de ellos contendrá una serie de registros y el otro contendrá el resto de registros existentes en el fichero de entrada debemos incluir las dos sentencias marcadas en malva.

     Esto sirve cuando tenemos un fichero de entrada en el que todos sus registros, empezando en la posición 18, hay una cadena de caracteres cuya longitud es 2 y los posibles valores son XX o XY. Al realizar lo indicado en el ejemplo tenemos que aquellos registros del fichero FICH.PRUEBA.ENTRADA que, empezando en la posición 18, contengan la cadena XX irán al fichero FICH.PRUEBA.SALID1 mientras que los que contangan la cadena XY irán al fichero FICH.PRUEBA.SALID2
     Si queremos generar ambos ficheros y además ordenarlos por un determinado campo debemos sustituir el SORT FIELDS=COPY por lo indicado en la entrada de título JCL: Ordenar un fichero mediante SORT.

lunes, 2 de abril de 2012

JCL: Eliminar/Incluir registros que cumplan una condición

     Para eliminar aquellos registros de un fichero que cumplan una determinada condición mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                     DISP=(,CATLG,DELETE),
          //                   SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY
              OMIT COND=(18,2,CH,EQ,C'99')

     Obsérvese que para eliminar los registros duplicados se utiliza lo siguiente OMIT COND=(18,2,CH,EQ,C'99') => esto supone que aquellos registros que, empezando en la posición 18, tengan una cadena cuyo valor sea 99 serán eliminados y, por tanto, no estarán en el fichero FICH.PRUEBA.SALIDA

     Para eliminar los que sean iguales a 99 o a otro valor como, por ejemplo, 09 tendríamos algo como lo siguiente:

          OMIT COND=(18,2,CH,EQ,C'99',OR,18,2,CH,EQ,C'09')

     Para incluir, es decir, para generar un fichero en el que tengamos aquellos registros que cumplan una condición habría que sustituir el OMIT por el INCLUDE. Ejemplos:

          INCLUDE COND=(18,2,CH,EQ,C'99')
          INCLUDE COND=(18,2,CH,EQ,C'99',OR,18,2,CH,EQ,C'09')

     Por lo tanto, el paso de SORT quedaría como se indica a continuación:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,

          //                     DISP=(,CATLG,DELETE),
          //                     SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY
              INCLUDE COND=(18,2,CH,EQ,C'99')


     Si queremos eliminar/incluir registros que cumplan una condición y además ordenar el fichero resultante debemos sustituir el SORT FIELDS=COPY por lo indicado en la entrada de título JCL: Ordenar un fichero mediante SORT.

viernes, 2 de marzo de 2012

JCL: Eliminar duplicados mediante SORT

     Para eliminar duplicados de un fichero mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                     DISP=(,CATLG,DELETE),
          //                     SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY
              SUM FIELDS=NONE

     Obsérvese que para eliminar los registros duplicados del fichero de entrada FICH.PRUEBA.ENTRADA se utiliza lo siguiente: SUM FIELDS=NONE
     En el fichero de salida FICH.PRUEBA.SALIDA tendremos una copia exacta del fichero FICH.PRUEBA.ENTRADA pero habiendo eliminado los registros duplicados.

     Si queremos eliminar duplicados y además ordenar el fichero resultante debemos sustituir el SORT FIELDS=COPY por lo indicado en la entrada de título JCL: Ordenar un fichero mediante SORT.

jueves, 2 de febrero de 2012

JCL: Copiar un fichero mediante SORT

Para copiar un fichero mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                    DISP=(,CATLG,DELETE),
          //                    SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY

Obsérvese que para copiar el fichero FICH.PRUEBA.ENTRADA se utiliza lo siguiente: SORT FIELDS=COPY => esto supone que vamos a hacer una copia exacta en el fichero de salida FICH.PRUEBA.SALIDA

14/12/2018 - Actualización. Ahora bien, si queremos copiar muchos archivos en uno solo, ¿cómo se haría? Muy fácil, partimos del ejemplo anterior y procedemos a copiar, por ejemplo, 5 ficheros en uno solo. El paso de sort quedaría así:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA1,DISP=SHR
          //              DD DSN=FICH.PRUEBA.ENTRADA2,DISP=SHR
          //              DD DSN=FICH.PRUEBA.ENTRADA3,DISP=SHR
          //              DD DSN=FICH.PRUEBA.ENTRADA4,DISP=SHR
          //              DD DSN=FICH.PRUEBA.ENTRADA5,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                    DISP=(,CATLG,DELETE),
          //                    SPACE=(CYL,1,1)
          //SORTWK01 DD SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=COPY

Como resultado tendríamos un fichero de salida, FICH.PRUEBA.SALIDA, en donde tendríamos la información de los 5 ficheros de entrada e iría concatenada una detrás de otra; es decir, primero irían los registros del primer fichero, después los registros del segundo fichero, a continuación los registros del tercer fichero, los del cuarto fichero y finalmente estarían los del quinto fichero.

lunes, 2 de enero de 2012

JCL: Ordenar un fichero mediante SORT

     Para ordenar un fichero mediante un paso de SORT se haría lo siguiente:

          //SORT01 EXEC PGM=SORT
          //SORTIN    DD DSN=FICH.PRUEBA.ENTRADA,DISP=SHR
          //SORTOUT DD DSN=FICH.PRUEBA.SALIDA,
          //                     DISP=(,CATLG,DELETE),
          //                     SPACE=(CYL,1,1)
          //SORTWK01 SPACE=(CYL,(1,1),RLSE)
          //SYSOUT     DD SYSOUT=*
          //SYSIN        DD *
              SORT FIELDS=(1,10,CH,A)

     Obsérvese que para ordenar el fichero FICH.PRUEBA.ENTRADA se utiliza lo siguiente: SORT FIELDS=(1,10,CH,A) => esto supone que se va a ordenar por un campo que empieza en la posición 1, dicho campo es de 10 posiciones, es un campo alfanumérico -CH- y se va a ordenar de forma ascendente -A-

     El resultado de la ordenación se guarda en el fichero FICH.PRUEBA.SALIDA

     Para ordenar de forma descendente habría que sustituir la A por una D.

     Ahora bien, ¿qué pasa sin en lugar de tener un campo alfanumérico (razón por la cual usamos CH) tenemos un campo cuyo tipo es distinto? Pues entonces tendríamos que sustituir CH por:
  • BI si el campo a ordenar es un campo numérico: PIC S9(-)
  • ZD si el campo a ordenar es un campo numérico: PIC 9(-)
  • PD si el campo a ordenar es un campo numérico empaquetado: PIC S9(-)COMP-3
Resumen: para ordenar un fichero en otro debemos utilizar lo siguiente:

               SORT FIELDS (X1,X2,TD,ORD)

siendo X1 la posición en la que empieza el campo a ordenar dentro del fichero
          X2 la longitud del campo a ordenar
          TD el tipo de dato del campo a ordenar (CH, ZD, PD,...)
          ORD el tipo de ordenación (A - Ascendente, D - Descendente)

viernes, 2 de diciembre de 2011

JCL: Introducción Sort

     En los JCL's es muy común incluir pasos en los que se utilice el comando SORT. El SORT no sólo es utilizado para ordenar un fichero sino también para realizar todo lo siguiente:
  • copiar de un fichero a otro
  • eliminar duplicados de un fichero
  • eliminar registros que cumplan una determinada condición
  • incluir registros que cumplan una determinada condición
  • obtener dos ficheros en los que cada uno de ellos tengamos registros distintos (por ejemplo, tenemos un fichero principal en el que los registros pueden clasificarse en dos grupos y los que pertenezcan a un grupo irán a un fichero y los que pertenezcan al otro grupo irán al otro fichero)
  • generar un fichero más pequeño debido a que quitamos los últimos campos del fichero principal
     En futuras entradas iremos viendo todas estas cosas y muchas más sobre el SORT.

miércoles, 2 de noviembre de 2011

Cobol: Varchar

     Recuerdo que en una ocasión tuve que crear un módulo de servicio para una tabla DB2 y esa tabla tenía un campo que era un varchar. A la hora de manejar ese campo me daban una serie de errores debido a un manejo incorrecto del mismo. Por lo tanto, ¿cómo se debe manejar un dato de tipo varchar para que no se produzcan errores? Contestaré a esta pregunta mediante un ejemplo.

     Supongamos que tenemos una tabla DB2 llamada TPEDIDOS. En esta tabla tenemos los siguientes campos:

                    01 TPEDIDOS.
                         05 COD-PED     PIC X(06).
                         05 FECHA-PED  PIC X(10).
                         05 PROVEEDOR PIC X(15).
                         05 COD-PROD   PIC 9(03).
                         05 DIR-ENV.
                             49 DIR-ENV-E-LEN   PIC S9(4) COMP.
                             49 DIR-ENV-E-TEXT PIC X(500).

     En azul se ha marcado el campo de tipo varchar.

     Supongamos que el módulo de servicio de la tabla TPEDIDOS (o rutina cobol para realizar las operaciones básicas sobre la tabla como SELECT, INSERT, UPDATE y DELETE) tiene la siguiente copy:


                    01 R-PEDIDOS.
                         05 ENTRADA.
                             10 E-COD-PED     PIC X(06).
                             10 E-FECHA-PED  PIC X(10).
                             10 E-PROVEEDOR PIC X(15).
                             10 E-COD-PROD   PIC 9(03).
                             10 E-DIR-ENV.
                                 15 E-DIR-ENV-E-LEN   PIC S9(4) COMP.
                                 15 E-DIR-ENV-E-TEXT PIC X(500).
                         05 SALIDA.
                             10 S-COD-RETORNO PIC 9(01).
                             10 S-COD-SQLCODE PIC 9(03).
                             10 S-COD-MENSAJE  PIC X(50).


     En azul se ha marcado el campo de tipo varchar.

     A continuación vamos a ver cómo se debe informar el campo de tipo varchar antes de llamar al módulo de servicio (Informar campo de tipo varchar) y cómo se ven afectadas las sentencias SQL en el módulo de servicio al utilizarse un campo de este tipo (Ejecución de sentencias SQL en el módulo de servicio).

Informar campo de tipo varchar

     En el caso de querer realizar un alta (INSERT) o modificación (UPDATE) de la tabla mediante el módulo de servicio, lo primero que hay que hacer antes de llamar al módulo de servicio para ejecutar la sentencia SQL correspondiente es informar el campo de tipo varchar de la copy del módulo de servicio tal y como se indica a continuación:

          MOVE 35                                                        TO E-DIR-ENV-E-LEN
          MOVE 'C\ DESCONOCIDA Nº7 NAVE 1D CP 28045' TO E-DIR-ENV-E-TEXT

     Nótese que se está asignando una cadena a E-DIR-ENV-E-TEXT y, como su longitud es 35, se está asignando dicho valor a E-DIR-ENV-E-LEN. Es muy importante que la longitud de la cadena coincida con el valor numérico que se está asignando a E-DIR-ENV-E-LEN porque de lo contrario, cuando se quisiera mostrar el valor de la dirección, no se mostraría el texto tal cual sino una cadena menor o mayor. Es decir, si en lugar de asignar a E-DIR-ENV-E-LEN la longitud de la cadena, que dijimos es 35, se le asigna:
  • un valor menor, por ejemplo 20, por mucho que asignemos el texto anterior a E-DIR-ENV-E-TEXT lo que se mostraría cuando se hiciera un display de la dirección es un texto de longitud 20 cuyo valor sería el siguiente: C\ DESCONOCIDA Nº7 N
  • un valor mayor, por ejemplo 40, por mucho que asignemos el texto anterior a E-DIR-ENV-E-TEXT lo que se mostraría cuando se hieciera un display del campo es un texto de longitud 40 cuyo valor sería el mostrado anteriormente (C\ DESCONOCIDA Nº7 NAVE 1D CP 28045) con espacios en blanco al final hasta rellenar las otras 5 posiciones
Ejecución de sentencias SQL en el módulo de servicio

     En el módulo de servicio hay que tener en cuenta los siguientes puntos para poder manejar correctamente ese campo:
  • Tanto en el alta (INSERT) como en la modificación (UPDATE) se deben informar los dos campos que forman parte de E-DIR-ENV tal y como se ha indicado anteriormente, es decir, el campo en el que se guarda la longitud del texto (E-DIR-ENV-E-LEN) y el campo en el que se guarda el texto (E-DIR-ENV-E-TEXT). A la hora de ejecutar la sentencia SQL correspondiente (INSERT o UPDATE), es la variable E-DIR-ENV la que se inserta y/o modifica.
  • Cuando se realiza la consulta (SELECT) se lee el campo de tipo varchar. Tras haber ejecutado la correspondiente sentencia SQL, lo que se hace es asignar el valor de cada uno de los campos que componen el campo de tipo varchar de la tabla (el de la longitud y el del texto) a los correspondientes campos de salida de la copy del módulo de servicio: las cuales son E-DIR-ENV-E-LEN y E-DIR-ENV-E-TEXT (E-DIR-ENV).

lunes, 3 de octubre de 2011

Manuales IBM

     Si pinchais aquí podreis encontrar una serie de manuales de IBM sobre mainframe (cobol, cics, jcl, db2) que espero os sean de utilidad. Eso sí, están inglés.

viernes, 9 de septiembre de 2011

Cobol: Utilizar sentencias SQL: eliminar.


     Para eliminar filas de una tabla lo haremos mediante la sentencia DELETE cuya sintaxis es la siguiente:

              DELETE FROM TABLA[WHERE CONDICIÓN]

     La cláusula WHERE se utiliza para borrar aquellas filas que cumplan dicha condición. Si no se utiliza esta cláusula se borraría la tabla entera.

jueves, 8 de septiembre de 2011

Cobol: Utilizar sentencias SQL: modificar.

     Para modificar filas en una tabla lo haremos mediante la sentencia UPDATE cuya sintaxis es la siguiente:

                 UPDATE TABLA SET {COLUMNA = VALOR,}[WHERE CONDICIÓN]

     En la cláusula SET indicaremos las columnas que queremos modificar y después del igual indicaremos el valor que queremos asignar.
     Con la cláusula WHERE indicaremos una condición de modo que sólo se modificarán las filas que cumplan dicha condición. Se puede omitir pero en este caso las modificaciones indicadas en la cláusula SET se aplicarían en todas las filas de la tabla.

miércoles, 7 de septiembre de 2011

Cobol: Utilizar sentencias SQL: seleccionar 2.

     Como indicamos en la anterior entrada, en la cláusula WHERE se utilizan una serie de operadores para construir la condición a emplear en dicha cláusula. Esos operadores son los operadores de comparación:

         1) Igualdad (=).
         2) Desigualdad (!=, <>, ^=).
         3) Menor que (<).
         4) Mayor que (>).
         5) Menor o igual que (<=).
         6) Mayor o igual que (>=).
         7) Igual a cualquiera de los miembros entre paréntesis (IN). Ejemplo:
                       WHERE COD_DEP IN (100, 200, 300)
         8) Distinto a cualquiera de los miembros entre paréntesis (NOT IN).
             Ejemplo:
         9) Contenido en el rango (BETWEEN). Ejemplo:
                       WHERE COD_EMP BETWEEN 100 AND 199
         10) Fuera del rango (BETWEEN). Ejemplo:
         11) Contiene una determinada cadena (LIKE). Cuando se utiliza el LIKE
               es frecuente el uso de los comodines. Dichos comodines pueden
               equivaler a un caracter ( _ ) o a varios caracteres (%): '_abc%',
               '%abc%', 'abc_' o 'abc%'. Ejemplo:
                       WHERE NOMBRE LIKE 'MA%';

     También existen operadores aritméticos u operadores de cadenas de caracteres. Los primeros pueden emplearse no sólo en la cláusula WHERE sino que también para mostrar información de una determinada manera a partir de las columnas existentes en las tablas. Mientras que los segundos se utilizan para mostrar información de una determinada manera a partir de las columnas existentes en las tablas (NO se utilizan en la cláusula WHERE).

     Dentro de los operadores aritméticos tenemos:

         1) Suma (+). Ejemplo:
                       SELECT NOMBRE, SALARIO+COMISION FROM EMPLEADO
                       WHERE OFICIO='VENDEDOR'
         2) Resta (-). Ejemplo:
                       SELECT NOMBRE FROM EMPLEADO
                       WHERE SYSDATE - FEC_ALTA > 365
         3) Producto (*). Ejemplo:
                       SELECT NOMBRE, SALARIO*12 FROM EMPLEADO
         4) División (/). Ejemplo:
                       SELECT NOMBRE, SALARIO/31 FROM EMPLEADO

     Dentro de los operadores de cadenas de caracteres tenemos:

         1) Concatenación (||). Ejemplo:
                       SELECT NOMBRE||OFICIO FROM EMPLEADO

                       WHERE COD_EMP NOT BETWEEN 100 AND 199
                       WHERE COD_DEP NOT IN (300, 500)

Cobol: Utilizar sentencias SQL: seleccionar 1.


     Para seleccionar filas en una tabla lo haremos mediante la sentencia SELECT cuya sintaxis es la siguiente:

              SELECT {*|{columna,}} FROM {TABLA,}[WHERE CONDICIÓN]
                         [ORDER BY {COLUMNA [ASC|DESC],}

     A tener en cuenta:


        1) Después de escribir SELECT debemos indicar * (se mostraría todas las columnas existentes en la tabla) o indicamos aquellas columnas que queremos ver. Ejemplos:

               SELECT * FROM TABLA


               SELECT COLUMNA3, COLUMNA7 FROM TABLA


        2) Después de escribir FROM debemos indicar la tabla o tablas de donde queremos ver la información. Ejemplos:


               SELECT * FROM TABLA1


               SELECT * FROM TABLA1, TABLA2

               SELECT A.COLUMNA1, B.COLUMNA8 FROM TABLA1 A, TABLA2 B


        3) Cláusula WHERE: se utiliza para seleccionar aquellas filas que cumplan la condición indicada. En esta cláusula se utilizan una serie de operadores que veremos en la siguiente entrada. Ejemplos:


               SELECT * FROM TABLA1 WHERE FECHA_ANTIG >= '20110101'


               SELECT A.NOMBRE, B.SALARIO FROM TABLA1 A, TABLA2 B
               WHERE (B.FECHA_ANTIG >= '20110101' AND
                           A.COD_EMPL = B.COD_EMPL)

        4) Cláusula ORDER BY: se utiliza para ordenar las filas devueltas por la select. Podemos indicar ASC para que muestre los datos ordenados de manera ascendente (de menor a mayor) o DESC para que muestre los datos ordenados de manera descendente (de mayor a menor). Ejemplos:


               SELECT * FROM TABLA1
               WHERE FECHA_ANTIG >= '20110101'
               ORDER BY FECHA_ANTIG         (1)


               SELECT * FROM TABLA1
               WHERE FECHA_ANTIG >= '20110101'
               ORDER BY FECHA_ANTIG ASC         (2)


               SELECT A.NOMBRE, B.SALARIO FROM TABLA1 A, TABLA2 B
               WHERE (B.FECHA_ANTIG >= '20110101' AND
                           A.COD_EMPL = B.COD_EMPL)
               ORDER BY B.FECHA_ANTIG DESC

               (1) y (2) son equivalentes.

lunes, 5 de septiembre de 2011

Cobol: Utilizar sentencias SQL: insertar.

     Para insertar filas en una tabla lo haremos mediante la sentencia INSERT cuya sintaxis es la siguiente:

                 INSERT INTO TABLA VALUES (VALOR1, VALOR2, ..., VALORN)