Mostrando entradas con la etiqueta cruce. Mostrar todas las entradas
Mostrando entradas con la etiqueta cruce. Mostrar todas las entradas

miércoles, 1 de junio de 2011

Cruce de 3 ficheros: cruce 1-1-1

Continuando con la saga de los programas de cruce, puede darse el caso de que queramos comparar tres ficheros en lugar de dos.

El ejemplo que vamos a ver es el más simple, donde la clave no se repite en ninguno de los ficheros, es decir, se trata de un cruce 1-1-1.

En nuestro ejemplo, el archivo principal será el número 2.
Podéis escoger cualquiera de ellos, porque lo que buscamos es que la clave existe en los tres.

La base del proceso de cruce sería:

EVALUATE TRUE

   WHEN Clave1 = Clave2 = Clave3
   WHEN Clave1 < Clave2
   WHEN Clave3 < Clave2
   WHEN Clave1 > Clave2
   WHEN Clave3 > Clave2

END-EVALUATE


En cada uno de los "WHEN" escribiremos el código de lo que queramos hacer. Por ejemplo, cuando las 3 claves coincidan, escribiremos un registro en el fichero de salida.



Al inicio del programa leeremos el primer registro de cada fichero e informaremos los campos Clave1, Clave2 y Clave3:
Clave1 = 1; Clave2 = 1; Clave3 = 1.

Repetiremos el proceso hasta el final de alguno de los tres ficheros (pues si llegamos al final de alguno de los ficheros, las 3 claves ya no coincidirán):

PERFORM 3000-PROCESO
  UNTIL FIN-FICHERO1
     OR FIN-FICHERO2
     OR FIN-FICHERO3


a) Clave1 = Clave2 = Clave3:
Realizamos las funciones necesarias. En nuestro ejemplo, escribir en un fichero de salida.
Leemos el siguiente registro de cada uno de los ficheros.
Clave1 = 2; Clave2 = 3; Clave3 = 2.

b) Clave1 < Clave2:
Esto significa que la Clave1 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 1 (el de menor clave).
Clave1 = 3; Clave2 = 3; Clave3 = 2.

c) Clave3 < Clave2:
Esto significa que la Clave3 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 3 (el de menor clave).
Clave1 = 3; Clave2 = 3; Clave3 = 5.

d) Clave3 > Clave2:
Esto significa que la Clave2 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 2 (el de menor clave).
Clave1 = 3; Clave2 = 5; Clave3 = 5.

e) Clave1 < Clave2:
Esto significa que la Clave1 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 1 (el de menor clave).
Clave1 = 6; Clave2 = 5; Clave3 = 5.

f) Clave1 > Clave2:
Esto significa que la Clave2 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 2 (el de menor clave).
Clave1 = 6; Clave2 = 6; clave3 = 5.

g) Clave3 < Clave2:
Esto significa que la Clave3 no existe en los 3 ficheros. Leemos el siguiente registro del fichero 3 (el de menor clave).
Clave1 = 6; Clave2 = 6; Clave3 = 6.


El proceso descrito se refiere al ejemplo del esquema "Curece 1-1-1 sencillo". Pero si os fijáis, lo importante al comparar las claves es leer siempre del fichero con menor clave, para ir posicionándonos correctamente sin dejar ninguna comparación por hacer.

Este ejemplo es MUY sencillo. Muchas veces cuando cruzamos 3 ficheros no buscamos los registros cuyas 3 claves coincidan, sino que puede ser que necesitemos los registros con Clave1 = Clave2 por un lado, y los registros con Clave3 = Clave2 por otro lado.

Aquí la cosa se complica (y ya no digamos si las claves se repiten n veces), porque ya no podemos hacer las lecturas en cada comparación, sino que tendremos que hacer las comparaciones necesarias en primer lugar, y las lecturas correspondientes al final del proceso.

Pero todo esto lo veremos en otro artículo : )

miércoles, 16 de marzo de 2011

EASYTRIEVE(I): Cruce ficheros 1:1

Este es le primero de una serie de artículos que presentaremos para explicar esta potente herramienta para el manejo de ficheros.

Empezaremos con un programa sencillo un cruce 1:1 de dos ficheros, para ello examinaremos el siguiente código EASYTRIEVE.

Supongamos el siguiente problema: Determinar que productos ha pedido al almacén un determinado empleado.

Para ellos contaremos con dos ficheros de información.
Fichero IN1 en el que tenemos la información de solicitudes de productos de empleados (producto viene especificado por su código):

FILE IN1
   IN1-NUMCLI          1    4 N 0
   IN1-NUMPROD         5    3 N 0
   IN1-FECALTA         8   10 A

Fichero IN2 en el que tenemos la información de las descripciones de los distintos productos:

FILE IN2
   IN2-NUMPROD         1    3 N 0
   IN2-DESPROD         4   14 A

Nuestro fichero de salida tendrá las decripciones de los productos de las solicitudes hechas por un empleado (lo que no se nos planteaba en el problema):

FILE OUT
   OUT-NUMCLI          1    4 N 0
   OUT-NUMPROD         5    3 N 0
   OUT-DESPROD         8   14 A

Vemos que se trata de un cruce 1:1 donde el campo clave (campo por el que se hace el cruce es el código del producto)
En el siguiente código se especifica los campos por los cuales se hace el enfrentamiento de los ficheros:

JOB INPUT (IN1 KEY (IN1-NUMPROD) +
          IN2 KEY (IN2-NUMPROD)) +
    FINISH PFINAL

Con la sentencia MATCHED tendremos todos aquellos registros donde el NUMPROD de IN1 = NUMPROD de IN2:

IF MATCHED
   OUT-NUMCLI = IN1-NUMCLI
   OUT-NUMPROD = IN1-NUMPROD
   OUT-DESPROD = IN2-DESPROD
   PUT OUT
END-IF
PFINAL . PROC
  DISPLAY '******************** FINAL ********************'
END-PROC

La sentencia PUT nos escribe en el fichero de salida

Nuestro problemas quedaría resuelto, pero vamos ir un poco mas allá, extrayendo un poco mas de información, para ver las posibilidades que nos ofrece EASYTRIEVE de una manera sencilla y muy rápida

IF NOT MATCHED Con esta sentencia tendremos todos aquellos registros donde el NUMPROD de IN1 <> NUMPROD de IN2

IF NOT MATCHED
   IF IN1 Con esta sentencia tendremos todos aquellos registros donde el NUMPROD de IN1 < NUMPROD de IN2
   IF IN2 Con esta sentencia tendremos todos aquellos registros donde el NUMPROD de IN1 > NUMPROD de IN2

Todo esto lo podemos ver mas claro viendo el siguiente ejemplo:
Supongamos el siguiente cruce de ficheros

 SECUEN.   IN1   IN2    

--------  ----- ------   
   1       1    N/A     
   2       2     2      
   3       3     3     
   4       4     4                
   5       5    N/A     
   6      N/A    6     
   7      N/A    7     
   8      N/A    8   
   9      N/A    9      
  10      N/A    10    
  11      11    N/A     
  12      12    N/A     
  13      13    N/A          
  14      14    N/A 

IF MATCHED Nos devolvería los registros cuyos secuenciales son: 2, 3, 4 

IF NOT MATCHED
   IF IN1 Nos devolvería los registros cuyos secuenciales son: 1, 5, 11, 12, 13, 14
   IF IN2 Nos devolvería los registros cuyos secuenciales son: 6, 7, 8, 9, 10

Esto es una manera sencilla y rápida de hacer un cruce de dos ficheros 1 a 1. En posteriores artículos veremos como tratar otro tipo de cruces 1:n y n:n.

En breve colgaremos para descargar el JCL, los ficheros de entrada, y el fichero de salida.

Y ahí lo tenéis:
JCL con easytrieve.

viernes, 14 de enero de 2011

ICETOOL(I): SPLICE; cruce de ficheros.

Vamos a publicar una serie de articulos sobre el uso del ICETOOL.
En esta ocasión explicaremos como cruzar dos fichero mediante un JCL, con ICETOOL.

Cruce de dos ficheros usando el comando SPLICE.

Vamos a hacer el caso de cruce 1:n  (un caso particular seria el caso 1:1)

Fichero IN1:
----+----1----+----2----+
4444 1111000021 1 YYYYYYYYY
4444 1111000021 2 QQQQQQQQQ
4444 1111000021 3 VVVVVVVVV
4444 1111000021 4 CCCCCCCCC
4444 1111000021 5 ZZZZZZZZZ
4444 1111000021 6 DDDDDDDDD

Fichero IN2:
----+----1----+----2----+----3----+
000000000 CCCCCCCCC 016 1111000021 010
000000000 QQQQQQQQQ 016 1111000021 020
000000000 ZZZZZZZZZ 016 1111000021 030
000000000 YYYYYYYYY 016 1111000021 050
000000000 VVVVVVVVV 016 1111000021 050
000000000 CCCCCCCCC 016 1111000021 090
000000000 XXXXXXXXX 016 1111000021 010


JCL que realiza el cruce:

//PASO010 EXEC PGM=ICETOOL
//TOOLMSG  DD SYSOUT=*
//DFSMSG   DD SYSOUT=*
//SHOWDEF  DD SYSOUT=*
//IN1      DD DISP=SHR,
//            DSN=USER.ICETOOL.IN1
//IN2      DD DISP=SHR,
//            DSN=USER.ICETOOL.IN2
//TMP      DD DSN=&&TEMP,DISP=(MOD,PASS),
//            SPACE=(TRK,(10,10)),UNIT=SYSDA
//OUT      DD DISP=(,CATLG),SPACE=(TRK,(10,10),RLSE),
//            DSN=USER.ICETOOL.OUT
//TOOLIN   DD *
  COPY FROM(IN1) TO(TMP) USING(CTL1)
  COPY FROM(IN2) TO(TMP) USING(CTL2)
  SPLICE FROM(TMP) TO(OUT) ON(1,10,CH) ON(11,9,CH) -
  WITH(21,3) WITH(24,1) WITHALL KEEPNODUPS USING(CTL3)
/*
//CTL1CNTL DD *
  INREC BUILD=(1:5,10,11:16,9,20:15,1,24:C'BB')
//CTL2CNTL DD *
  INREC BUILD=(1:22,10,11:10,9,21:32,3,24:C'VV')
//CTL3CNTL DD *
  OUTFIL FNAMES=OUT,INCLUDE=(24,2,CH,EQ,C'VB'),OUTREC=(1,23)
/*

La idea básica para la realización del cruce consiste en usar un fichero de apoyo (un fichero temporal) que una ambos ficheros, donde la clave de cruce estará en la misma posición para todos los registros de los ficheros IN1 e IN2.
Para lograr esto utilizaremos la sentencia COPY con la ayuda del USING, que nos permitirá usar "reglas de copiado" (en este caso hemos usando INREC, pero podriamos usar otras formas como OUTREC, condicionales IFTHEN, OVERLAY, ....).

Para el IN1 tenemos :
COPY FROM(IN1) TO(TMP) USING(CTL1)
...
//CTL1CNTL DD *
  INREC BUILD=(1:5,10,11:16,9,20:15,1,24:C'BB')

----+----1----+----2----+
4444 1111000021 1 YYYYYYYYY
4444 1111000021 2 QQQQQQQQQ
4444 1111000021 3 VVVVVVVVV
4444 1111000021 4 CCCCCCCCC
4444 1111000021 5 ZZZZZZZZZ
4444 1111000021 6 DDDDDDDDD

Para el IN2 tenemos:
COPY FROM(IN1) TO(TMP) USING(CTL1)
....
//CTL2CNTL DD *
  INREC BUILD=(1:22,10,11:10,9,21:32,3,24:C'VV')

----+----1----+----2----+----3----+
000000000 CCCCCCCCC 016 1111000021 010
000000000 QQQQQQQQQ 016 1111000021 020
000000000 ZZZZZZZZZ 016 1111000021 030
000000000 YYYYYYYYY 016 1111000021 050
000000000 VVVVVVVVV 016 1111000021 050
000000000 CCCCCCCCC 016 1111000021 090
000000000 XXXXXXXXX 016 1111000021 010

El fichero temporal tendría la siguiente estructura:
----+----1----+----2----+
1111000021 YYYYYYYYY 1 BB   Este registro viene del fichero IN1
1111000021 QQQQQQQQQ 2 BB   Este registro viene del fichero IN1
1111000021 QQQQQQQQQ 030 VV   Este registro viene del fichero IN2
1111000021 VVVVVVVVV 3 BB   Este registro viene del fichero IN1
1111000021 CCCCCCCCC 4 BB   Este registro viene del fichero IN1
1111000021 CCCCCCCCC 020 VV   Este registro viene del fichero IN2
...


SPLICE FROM(TMP) TO(OUT) ON(1,10,CH) ON(11,9,CH) -
WITH(21,3) WITH(24,1) WITHALL KEEPNODUPS USING(CTL3)

IMPORTANTE: aunque acabemos de ver una estructura de fichero ordenada, la sentencia COPY no ordena. Será la sentencia SPLICE la que antes de realizar el cruce ordene por la clave especificada.

SPLICE.
Aquí nos detendremos para explicar cada una de las sentencias que acompañan a la sentencia SPLICE.

SPLICE FROM(TMP) TO(OUT) ON(1,10,CH) ON(11,9,CH) -
  WITH(21,3) WITH(24,1) WITHALL KEEPNODUPS USING(CTL3)
...
//CTL3CNTL DD *
  OUTFIL FNAMES=OUT,INCLUDE=(24,2,CH,EQ,C'VB')

  • Sentencia ON(posicion inicial, longitud, tipo).
    Esta sentencia nos permite especificar las claves de cruce. En este caso tenemos dos [ON(1,10,CH) ON(11,9,CH)]
  • Sentencia WITH(posicion inicial, longitud).
    Especificaremos aquellos campos del fichero IN2 que queramos que se vean en el fichero de salida. El resto de posiciones del fichero de salida se rellenarán con los campos del fichero IN1. En este caso hemos eligido 2 [WITH(21,3) WITH(24,1)]:

    ----+----1----+----2----+
    1111000021 CCCCCCCCC 4 B B
    1111000021 CCCCCCCCC 020 V V

Antes de seguir vamos a hacer un breve parentesis para explicar los últimos campos añadidos para el fichero IN1 'BB' y para el fichero IN2 'VV'.
Tiene dos funciones:
  1. Identificar en el fichero de salida los registros que provienen de cada fichero de entrada.
  2. Identificar los registros que se han cruzado con éxito.
    Al especificar con el WITH la primera posición del fichero IN2 [WITH(24,1)], cuando dos registros tengan la misma clave el registro de salida vendrá marcado en las dos últimas posiciones con VB.
Asi:
  1. Registros con las dos últimas posiciones BB son aquellos registros del fichero de entrada IN1 que no encontraron correspondencia en el fichero de entrada IN2
  2. Registros con las dos últimas posiciones VV son aquellos registros del fichero de entrada IN2 que no encontraron correspondencia en el fichero de entrada IN1
  3. Registros con las dos últimas posiciones VB son aquellos registros que tuvieron correspondencia.

    ----+----1----+----2----+
    1111000021 CCCCCCCCC 1 020 V B

  • Sentencia WITHALL.
    En el caso de que una clave esté más de una vez en el fichero IN2, podemos especificar WITHALL para recoger todos los registros que la contengan. Si no se especifica se quedaría con el primero.
Ejemplo:
El registro del fichero IN1:
----+----1----+----2----+
1111 1111000021 4 CCCCCCCCC

Tiene la siguiente correspondencia en el fichero IN2:
----+----1----+----2----+----3----+
000000000 CCCCCCCCC 016 1111000021 010
000000000 CCCCCCCCC 016 1111000021 090

Se almacena en el fichero temporal:
----+----1----+----2----+
1111000021 CCCCCCCCC 4 BB   Registro del fichero IN1
1111000021 CCCCCCCCC 020 VV   Registro del fichero IN2
1111000021 CCCCCCCCC 090 VV   Registro del fichero IN2

Si nosotros no especificásemos WITHALL veríamos la salida:
----+----1----+----2----+
1111000021 CCCCCCCCC 4 020 V B

Si nosotros SI especificásemos WITHALL veríamos la salida:
----+----1----+----2----+
1111000021 CCCCCCCCC 4 020 V B
1111000021 CCCCCCCCC 4 090 V B

  • Sentencia KEEPNODUPS.
    Se utiliza para mostrar en el fichero de salida, los registro del fichero IN1 cuya clave no existe en el fichero IN2.

Ejemplo:
El registro del fichero IN1:
----+----1----+----2----+
1111 1111000021 6 DDDDDDDDD

Se almacena en el fichero temporal:
----+----1----+----2----+
1111000021 DDDDDDDDD 6     BB   Registro del fichero IN1

Para nuestra clave sólo hay un registro (no encontró coincidencia en el fichero IN2).
Si nosotros no especificásemos KEEPNODUPS, no veríamos el registro en la salida.

Si lo especificamos veríamos el siguiente registro en la salida:
----+----1----+----2----+
1111000021 DDDDDDDDD 6     B B

  • Sentencia USING.
    También fue usada cuando copiábamos los ficheros al temporal. Podríamos decir que son unas "reglas de copiado" para definir el fichero de salida. En este caso:
    • OUTFIL, para generar el fichero de salida OUT.
    • INCLUDE, para seleccionar aquellos registros que se cruzaron.
    • OUTREC, para eliminar las dos últimas posiciones de trabajo.

Esto es una manera sencilla y rapida de hacer un cruce de dos ficheros.
Es importante asegurarse de que el fichero de entrada no tenga duplicados por clave, es decir, es un cruce 1 a n.

Para terminar, os dejo para descargar el JCL, los ficheros de entrada, y el fichero de salida:
JCL con ICETOOL.
Fichero IN1.
Fichero IN2.
Fichero OUT.

martes, 2 de noviembre de 2010

Cruce n-n: la cosa se complica.

En un programa de cruce n-n, las claves de ambos ficheros pueden venir repetidas n veces.
Puede ocurrir que, a pesar de que la clave esté repetida, sólo nos interese comprobar que coinciden 1 vez, que sería el caso más sencillo.
Si por el contrario necesitamos recuperar todos los registros con la misma clave de los 2 ficheros, la cosa se complicaría un poco más.

Vamos a empezar por el caso fácil: Cruce n-n simple.



En el INICIO del programa, leeremos el primer registro de cada fichero e informaremos los campos CLAVE1 y CLAVE2:
CLAVE1 = 1; CLAVE2 = 1.
Repetiremos el proceso hasta llegar al final de alguno de los 2 ficheros.

a) CLAVE1 = CLAVE2:
Hacemos el tratamiento de datos
Leemos del fichero 1 hasta que cambie CLAVE1:

PERFORM UNTIL CLAVE1 <> CLAVE1-ANTERIOR(que valía 1)
Leemos el siguiente registro del fichero 1 e informamos CLAVE1 con el siguiente valor.
Cuando lleguemos a CLAVE1 = 2 saldremos del bucle
END-PERFORM

CLAVE1 = 2

Leemos del fichero 2 hasta que cambie CLAVE2:

PERFORM UNTIL CLAVE2 <> CLAVE2-ANTERIOR(que valía 1)
Leemos el siguiente registro del fichero 1 e informamos CLAVE1 con el siguiente valor.
Cuando lleguemos a CLAVE2 = 3 saldremos del bucle
END-PERFORM

CLAVE2 = 3

b) CLAVE1 < CLAVE2:
Esto significa que la CLAVE1 no existe en el fichero 2. Leemos el siguiente registro del fichero 1.

c) CLAVE1 > CLAVE2:
Esto significa que la CLAVE2 no existe en el fichero 1.
Leemos el siguiente registro del fichero 2.

En este caso lo único que hacemos es saltarnos los registros repetidos pues sólo vamos a tratar 1 vez cada CLAVE.

Vamos con el caso difícil: Cruce n-n complejo.



En el INICIO del programa:
Leeremos el primer registro del fichero 1 y del fichero 2.
Guardo todos los registros del fichero 2 que tengan la misma clave en una tabla interna.
CLAVE1 = 1; CLAVE2-tabla interna = 1.

Repetiremos el proceso hasta llegar al final de alguno de los 2 ficheros:

a) CLAVE1 = CLAVE2-tabla interna(1):
Comparamos cada registro del fichero 1, con todos los registros del fichero 2 guardados en la tabla interna:



PERFORM UNTIL CLAVE1 <> CLAVE1-ANTERIOR(que valía 1)
PERFORM UNTIL clave de la tabla interna vacía o superamos el máximo de ocurrencias
Hacemos el tratamiento de los datos
Añadimos 1 al índice
END-PERFORM

Inicializamos el índice de la tabla a 1
Leemos siguiente registro del fichero 1:cuando lleguemos a CLAVE1 = 2 saldremos del bucle
END-PERFORM

CLAVE1 = 2
Guardo los siguientes registros del fichero 2 que tengan la misma clave en la tabla interna:
CLAVE2-tabla interna = 3

b) CLAVE1 < CLAVE2-tabla interna:
Esto significa que la CLAVE1 no existe en el fichero 2. Leemos el siguiente registro del fichero 1: CLAVE1 = 5. CLAVE2-tabla interna sigue valiendo 3.

c) CLAVE1 > CLAVE2-tabla interna:
Esto significa que la CLAVE2 no existe en el fichero 1.
Guardo los siguientes registros del fichero 2 que tengan la misma clave en la tabla interna:
CLAVE2-tabla interna = 3

Una forma de guardar los registros en la tabla interna sería:
PERFORM UNTIL CLAVE2 <> CLAVE2-ANTERIOR
Muevo los campos a la tabla interna
Leo el siguiente registro del fichero 2
END-PERFORM

Y queda listo nuestro programa de cruce n-n. Toma ya!

A petición popular, os dejo un ejemplo completo, con su JCL, y con la información de los ficheros de entrada y de salida:
Programa de cruce n-n.
JCL de ejecución.
Ficheros de entrada y salida.

Cruce 1-n: subiendo el nivel.

El programa de cruce 1-n se basa en el mismo proceso que el cruce 1-1. La diferencia está en que la clave del fichero 2 puede venir repetida n veces. Y como para muestra un botón, ahí va otro ejemplo:



En el INICIO del programa, leeremos el primer registro de cada fichero e informaremos los campos CLAVE1 y CLAVE2: CLAVE1 = 1; CLAVE2 = 1.

Repetiremos el proceso hasta llegar al final de alguno de los 2 ficheros.

a) CLAVE1 = CLAVE2:
Dentro de un bucle, hacemos el tratamiento que corresponda y leemos del fichero 2 hasta que cambie el valor del campo CLAVE2.

PERFORM UNTIL CLAVE2 <> CLAVE2-ANTERIOR(que valía 1)
Tratamiento de datos.
Leemos el siguiente registro del fichero 2 e informamos CLAVE2 con el siguiente valor.
Cuando lleguemos a CLAVE2 = 3 saldremos del bucle
END-PERFORM

b) Fuera del bucle(CLAVE2 ha cambiado, vale 3), leemos el siguiente registro del fichero 1:
CLAVE1 = 2.

c) CLAVE1 < CLAVE2:
Esto significa que la CLAVE1 no existe en el fichero 2. Leemos el siguiente registro del fichero 1.
CLAVE1 = 5. CLAVE2 sigue valiendo 3.

d) CLAVE1 > CLAVE2:
Esto significa que la CLAVE2 no existe en el fichero 1. Leemos el siguiente registro del fichero 2.
CLAVE1 = 5. CLAVE2 = 5.

La diferencia principal con el cruce 1-1 está en el caso a), pues ahora tendremos que tratar todos los registros del fichero 2 que tengan la misma clave antes de tratar el siguiente registro del fichero 1.

Mi primer programa de cruce. Cruce 1-1.

El programa de cruce de ficheros más sencillo es el denominado 1-1. Esto significa que el valor de los campos que vamos a comparar sólo estará una vez en cada fichero.

El campo de comparación se suele llamar "campo clave" o simplemente "clave". Este campo clave existirá en ambos ficheros y tendrá el mismo formato (PIC) en ambos. De no ser así tendríamos que formatear uno de ellos para que coincidan los formatos.

OJO! los ficheros de un programa de cruce siempre vendrán ordenados por el campo clave.

JCL:

//******************************************************
//******************** BORRADO *************************
//BORRADO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEL FICHERO.ENTRADA1.ORDENADO

DEL FICHERO.ENTRADA2.ORDENADO
DEL FICHERO.SALIDA.CRUCE
SET MAXCC = 0
//******************************************************
//* ORDENAMOS EL FICHERO ENTRADA1 POR CLAVE *********
//SORT01 EXEC PGM=SORT
//SORTIN   DD DSN=FICHERO.ENTRADA1,DISP=SHR
//SORTOUT  DD DSN=FICHERO.ENTRADA1.ORDENADO,
//            DISP=(,CATLG),SPACE=(TRK,(50,10))
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
  SORT FIELDS=(1,1,CH,A)

//******************************************************
//* ORDENAMOS EL FICHERO ENTRADA2 POR CLAVE *********
//SORT01 EXEC PGM=SORT
//SORTIN   DD DSN=FICHERO.ENTRADA2,DISP=SHR
//SORTOUT  DD DSN=FICHERO.ENTRADA2.ORDENADO,
//            DISP=(,CATLG),SPACE=(TRK,(50,10))
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
  SORT FIELDS=(1,1,CH,A)

//******************************************************
//*********** EJECUCION DEL PROGRAMA PRUEBA7 ***********
//PROG4 EXEC PGM=PRUEBA7
//SYSOUT  DD SYSOUT=*
//FICHERO1 DD DSN=FICHERO.ENTRADA1.ORDENADO,DISP=SHR
//FICHERO2 DD DSN=FICHERO.ENTRADA2.ORDENADO,DISP=SHR
//SALIDA   DD DSN=FICHERO.SALIDA.CRUCE,
//            DISP=(NEW, CATLG, DELETE),SPACE=(TRK,(50,10)),
//            DCB=(RECFM=FB,LRECL=1)
/*


Programa:
La base del proceso de un programa de cruce es la comparación de las claves:

3000-PROCESO.

EVALUATE TRUE
   WHEN CLAVE1 = CLAVE2

        (...)
   WHEN CLAVE1 < CLAVE2

        (...)
   WHEN CLAVE1 > CLAVE2

        (...)
END-EVALUATE
.


En cada WHEN pondremos el código de lo que queremos hacer. Por ejemplo, cuando las claves coincidan, escribiremos un registro en un fichero de salida.

EVALUATE TRUE
   WHEN CLAVE1 = CLAVE2

        PERFORM ESCRIBE-SALIDA-CRUCE
        PERFORM LEER-FICHERO1
        PERFORM LEER-FICHERO2
   WHEN CLAVE1 < CLAVE2

        DISPLAY 'CLAVE1 NO EXISTE EN FICHERO2'
        PERFORM LEER-FICHERO1
   WHEN CLAVE1 > CLAVE2

        DISPLAY 'CLAVE2 NO EXISTE EN FICHERO1'
        PERFORM LEER-FICHERO2
END-EVALUATE
.


Este proceso se repetirá X veces dependiendo del tratamiento que queramos hacer:
1.Proceso hasta final del fichero 1: cuando queremos tratar todos los registros del fichero 1, existan o no en el fichero 2.
2.Proceso hasta final del fichero 1 y final del fichero 2: cuando queremos tratar todos los registros de los 2 ficheros. Esto incluye los registros comunes a ambos ficheros, los registros del fichero 1 que no están en el fichero 2 y los registros del fichero 2 que no están el fichero 1.
3.Proceso hasta final del fichero 1 o final del fichero2: cuando sólo queremos tratar los registros coincidentes. En el momento en que uno de los ficheros se termine, no volveremos a tener claves coincidentes por lo que no tiene sentido continuar la ejecución.

Para verlo más claro pongamos un ejemplo:

En el INICIO del programa, leeremos el primer registro de cada fichero e informaremos los campos CLAVE1 y CLAVE2:

1000-INICIO.


    PERFORM LEER-FICHERO1
    PERFORM LEER-FICHERO2
    .


Donde:
LEER-FICHERO1.
    

    READ FICHERO1 INTO WX-ENTRADA1

    EVALUATE FS-FICHERO1
       WHEN ZEROES
            MOVE WX-ENTRADA1 TO CLAVE1
       WHEN 10
            SET FIN-FICHERO1 TO TRUE
       WHEN OTHER
            PERFORM 3000-FINAL
    END-EVALUATE
    .

LEER-FICHERO2.
Lo mismo que para Fichero1.


Después de la primera lectura:
CLAVE1 = 1; CLAVE2 = 1.

Repetiremos el proceso hasta llegar al final de alguno de los 2 ficheros.
PERFORM 3000-PROCESO
  UNTIL FIN-FICHERO1
     OR FIN-FICHERO2


a) CLAVE1 = CLAVE2:
Escribimos en el fichero de salida:
ESCRIBIR-SALIDA-CRUCE.
    MOVE CLAVE1 TO WX-SALIDA

    WRITE REG-SALIDA FROM WX-SALIDA

    IF FS-SALIDA-OK
       INITIALIZE WX-SALIDA
    ELSE
       DISPLAY 'ERROR EN WRITE DEL FICHERO:'FS-SALIDA
    END-IF 

    .

Leemos el siguiente registro del fichero 1: PERFORM LEER-FICHERO1
CLAVE1 = 2.
Leemos el siguiente registro del fichero 2: PERFORM LEER-FICHERO2
CLAVE2 = 3.

b) CLAVE1 < CLAVE2:
Esto significa que la CLAVE1 no existe en el fichero 2.
Leemos el siguiente registro del fichero 1: PERFORM LEER-FICHERO1
CLAVE1 = 5.

c) CLAVE1 > CLAVE2:
Esto significa que la CLAVE2 no existe en el fichero 1.
Leemos el siguiente registro del fichero 2: PERFORM LEER-FICHERO2
CLAVE2 = 5.

El tratamiento que hagamos en cada uno de los casos es indiferente para el proceso de cruce. Lo importante es el orden en el que leemos los ficheros.

Para terminar vamos a ver como serían las lecturas en caso de que el proceso se repita hasta final de los dos ficheros:
LEER-FICHERO1.
    READ FICHERO1 INTO WX-ENTRADA1

    EVALUATE FS-FICHERO1
       WHEN ZEROES
            MOVE WX-ENTRADA1 TO CLAVE1
       WHEN 10
            SET FIN-FICHERO1 TO TRUE
            

            MOVE HIGH-VALUES TO CLAVE1
       WHEN OTHER
            PERFORM 3000-FINAL
    END-EVALUATE
    .


LEER-FICHERO2.
Lo mismo que para Fichero1.


Como podéis ver hemos informado la clave con HIGH-VALUES. Esto significa que cuando finalize el fichero1, la CLAVE1 va a ser siempre mayor que la clave 2, y en el EVALUATE donde comparamos las claves, siempre entrará por el tercer WHEN.
Una vez leido todo el fichero1, el programa seguirá ejecutándose leyendo del fichero2, hasta que éste también finalice.

Y ya está, nuestro primer programa de cruce está listo : )