Mostrando entradas con la etiqueta matching. Mostrar todas las entradas
Mostrando entradas con la etiqueta matching. 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 : )

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 : )