ACTUALIZADO: corregido el error que daba cuando el fichero no existía.
En esta ocasión os traemos un programa REXX, pequeño, fácil y para toda la familia. Con él podremos entrar a "ver" o "editar" un fichero desde el JCL, sólo con posicionar el cursor encima del nombre del fichero.
Unos lo llamarán comodidad, otros vagancia^^
Veamos el código REXX:
/* REXX */
/*EDIT DE FICHERO SEGUN POSICION DEL CURSOR DSN= */
MENSA=MSG('OFF')
"PROFILE NOPREFIX"
TRACE OFF
ARG A_OPC .
ADDRESS ISPEXEC "ISREDIT MACRO"
ADDRESS ISPEXEC "ISREDIT (LIN,COL) = CURSOR "
ADDRESS ISPEXEC "ISREDIT (LINEA) = LINE " LIN
X=OPCION() /* IDENTIFICAR OPCIÓN */
X=BFILE() /* BUSCA NOMBRE */
X=VFILE() /* VALIDA FILE */
RETURN 0
OPCION: /* IDENTIFICA LA OPCIóN ELEGIDA, EDIT O VIEW */
IF A_OPC = '' THEN
DO
SAY 'SELECCIONE OPCIóN: E (EDITAR) ó V (VIEW)'
PARSE EXTERNAL A_OPC .
IF A_OPC = '' THEN
EXIT
UPPER A_OPC
END
RETURN 0
BFILE: /* BUSCA NOMBRE FICHERO EN LA LINEA */
F = INDEX(LINEA,'DSN=')
IF F=0 THEN
DO
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,',')
FILE=STRIP(FILE,,"'")
F=INDEX(FILE,"')")
IF F=0 THEN
DO
FILE=SUBSTR(FILE,1,F-1)
END
END
ELSE
DO
FILE=SUBWORD(SUBSTR(LINEA,F+4),1,1)
F=INDEX(FILE,',')
IF F<>0 THEN
DO
FILE = SUBSTR(FILE,1,F-1)
END
F = INDEX(FILE,'(')
IF F <> 0 THEN
DO
/*-- EXTRAER VERSION DEL GDG --*/
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1)
IF SUBSTR(GDGVERS, 1, 1) = '+' THEN
IN = 0
ELSE
DO
IF SUBSTR(GDGVERS, 1, 1) = '-' THEN
IN = SUBSTR(GDGVERS, 2, LENGTH(GDGVERS)-1)
ELSE
IN = 0
END
FILE = SUBSTR(FILE,1,F-1)
/*-- LISTA TODAS LAS VERSIONES DEL GDG. --*/
Q = OUTTRAP(DATA.)
"LISTC ENT('"||FILE||"')"
Q = OUTTRAP(OFF)
/*-- DETERMINA EL NOMBRE DE LA VERSION ACTUAL --*/
REC = DATA.0 -(2*IN+1)
PARSE VAR DATA.REC . . FILE
END
END
FILE=STRIP(FILE,,' ')
RETURN 0
VFILE: /* VALIDA FILE */
IF SYSDSN(FILE) <> 'OK' THEN
ADDRESS ISPEXEC "ISREDIT LINE_AFTER "LIN" = MSGLINE <1>"
ELSE
DO
IF A_OPC = 'E' THEN
ISPEXEC "EDIT DATASET('"FILE"')"
IF A_OPC = 'V' THEN
ISPEXEC "VIEW DATASET('"FILE"')"
END
RETURN 0
Donde:
ARG A_OPC:
Variable donde guardaremos la opción "E" o "V"
"ISREDIT MACRO":
Es una macro
"ISREDIT (LIN,COL) = CURSOR ":
Posición del cursor
"ISREDIT (LINEA) = LINE " LIN:
Línea
PARSE EXTERNAL A_OPC:
Guarda el valor introducido en la variable A_OPC
INDEX(LINEA,'DSN='):
El nombre del fichero estará después del 'DSN='.
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,','):
Recupera la cadena de caracteres que contiene el nombre del fichero.
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1):
Recupera la versión en la que estamos para el caso de que el fichero sea un GDG. Por ejemplo (-1).
SUBSTR(GDGVERS, 1, 1) = '+' THEN IN = 0:
Para las versiones positivas mostraremos la última versión del GDG.
SUBSTR(GDGVERS, 1, 1) = '-':
Si se trata de versiones negativas del GDG calculamos a cual corresponde.
"EDIT DATASET('"FILE"')":
Abre el fichero en modo EDIT.
"VIEW DATASET('"FILE"')":
Abre el fichero en modo VIEW.
Para ejecutar el programa tenemos dos opciones:
1. Escribir en la linea de comando el nombre del programa (por ejemplo REXEDI), colocar el cursor encima del nombre del fichero que queremos abrir y pulsar intro. Elegimos E o V y damos intro.
2. Guardar el nombre del programa REXX en una de nuestras KEYS. Colocamos el cursor encima del nombre del fichero y pulsar intro. Elegimos E o V y damos intro.
En el caso de que no os funcione, habrá que hacer esta comprobación:
En la línea de comandos escribimos "TSO ISRDDN". Nos saldrá algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
TSST50 NEW,DEL > ISPCTL0 LIBRERIA1
CXDR21 SHR,KEEP > ISPILIB LIBRERIA2
MVSC04 SHR,KEEP > ISPLLIB LIBRERIA3
CXDR21 SHR,KEEP > LIBRERIA4
MVSC04 SHR,KEEP > ISPMLIB LIBRERIA5
(...)
Buscaremos SYSEXEC escribiendo "O SYSEXEC". Nos mostrará algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
CXDS01 SHR,KEEP > SYSEXEC LIBRERIA6
MVSC09 SHR,KEEP > LIBRERIA7
PSTS01 SHR,KEEP > LIBRERIA8
MVSC09 SHR,KEEP > LIBRERIA9
Nuestro programilla REXX deberá estar en una de las librerías del SYSEXEC. La razón es que lo que estamos ejecutando es en realidad una macro.
Si se da el caso de que no tenemos acceso a ninguna de las librerías del SYSEXEC podemos añadir una nuestra. Para ello tenemos el siguiente código:
CONTROL NOFLUSH LIST
ALLOC F(SYSEXEC) SHR REUSE DA('LIBRERIA6' +
'LIBRERIA7' +
'LIBRERIA8' +
'LIBRERIA9' +
'MILIBRERIA')
que escribiremos en un fichero (es un CLIST).
Lo ejecutaremos con un TSO EX FICHERO.CON.CODIGO.ANTERIOR.
Ahora al consultar el ISRDDN veremos que ya aparece en el SYSEXEC nuestra librería.
Perfecto, ya podemos ejecutar macros!
Si preferís que no os pida elegir entre editar "E" o visualizar "V", podemos tener dos macros: una para edit y otra para view.
Guardando el nombre de la macro en una de las KEYS, o escribiéndolo en la línea de comandos, sólo tendremos que posicionarnos en el nombre del fichero que queremos ver y dar intro. Según estemos ejecutando la macro de edit o la de view nos abrirá el fichero en edición o visualización respectivamente.
ACTUALIZADO: corregido el error que daba cuando el fichero no existía.
Os dejo la última versión del código REXX para la opción de editar:
Descargar EDI-FILE
Si tenéis cualquier problema con esto nos contáis e intentamos solucionarlo : )
Mostrando entradas con la etiqueta pepegan. Mostrar todas las entradas
Mostrando entradas con la etiqueta pepegan. Mostrar todas las entradas
lunes, 21 de mayo de 2012
lunes, 17 de octubre de 2011
Comandos TSO vol.3: línea de comandos.
En esta tercera parte de comandos TSO, explicaremos los comandos que se usan desde la linea de comandos:
BOOKMARKS en el editor de TSO.
Antes de empezar a comentar estos comandos, haremos una explicación sobre los bookmarks en un editor de texto.
Para poder crear un bookmark en una determinada linea de texto, sobre la columna que indica el numero de linea escribimos . seguido de un literal.
000010 Texto A
.A0011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
.A Texto B
000012 Texto C
000013 Texto D
Con esto hemos creado un marcador en nuestro texto.
A continuación vamos a ver la utilidad de estos marcadores.
Comandos básicos.
LINE. Comando linea
El comando LINE o de una forma abreviada L, es el primer comando de esta nueva entrega.
Se usa a través de la línea de comando, y su objetivo es ir a una linea concreta de nuestro texto.
Command ===> L 11
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
000011 Texto B
000012 Texto C
000013 Texto D
Si tuvieramos un marcador por ejemplo en la línea 12, podriamos usar el comando LINE con el marcador
Command ===> L .A
000010 Texto A
000011 Texto B
.A Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
.A Texto C
000013 Texto D
FIND. Busca un texto.
El comando FIND o de una forma abreviada F tiene como objetivo buscar una cadena de texto.
Command ===> F 'Te'
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Vamos a combinar el comando FIND con los marcadores anteriormente comentados
Supongamos dos marcadores por ejemplo en las líneas 10 y 12, podemos el comando FIND para buscar texto entre un rango de líneas
Command ===> F 'Te' .A .B
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Vamos un poco más allá. Vamos a combinar este comando con el comando BNDS mencionado en el articulo anterior.
Supongamos que queremos buscar una cadena de texto en una porción de texto usaremos el comando FIND con los marcadores y BNDS.
Queremos buscar la t entre las columnas 3 y 6 y entre las líneas 10 y 12.
1.-Tecleamos el comando COLS, para saber las posición de las columnas
2.-Tecleamos el comando BNDS, para establecer el intervalo (de columnas) en el que buscar
3.-Establecemos dos marcadores. Uno en la línea 10 y otro en la línea 12.
4.-Tecleamos el comando F t .A .B
Veamoslo en nuestro editor:
Command ===> F 't' .A .B
=COLS> ----+----1---
=BNDS> < >
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
=COLS> ----+----1---
=BNDS> < >
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
BOOKMARKS en el editor de TSO.
Antes de empezar a comentar estos comandos, haremos una explicación sobre los bookmarks en un editor de texto.
Para poder crear un bookmark en una determinada linea de texto, sobre la columna que indica el numero de linea escribimos . seguido de un literal.
000010 Texto A
.A0011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
.A Texto B
000012 Texto C
000013 Texto D
Con esto hemos creado un marcador en nuestro texto.
A continuación vamos a ver la utilidad de estos marcadores.
Comandos básicos.
LINE. Comando linea
El comando LINE o de una forma abreviada L, es el primer comando de esta nueva entrega.
Se usa a través de la línea de comando, y su objetivo es ir a una linea concreta de nuestro texto.
Command ===> L 11
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
000011 Texto B
000012 Texto C
000013 Texto D
Si tuvieramos un marcador por ejemplo en la línea 12, podriamos usar el comando LINE con el marcador
Command ===> L .A
000010 Texto A
000011 Texto B
.A Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
.A Texto C
000013 Texto D
FIND. Busca un texto.
El comando FIND o de una forma abreviada F tiene como objetivo buscar una cadena de texto.
Command ===> F 'Te'
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Vamos a combinar el comando FIND con los marcadores anteriormente comentados
Supongamos dos marcadores por ejemplo en las líneas 10 y 12, podemos el comando FIND para buscar texto entre un rango de líneas
Command ===> F 'Te' .A .B
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Vamos un poco más allá. Vamos a combinar este comando con el comando BNDS mencionado en el articulo anterior.
Supongamos que queremos buscar una cadena de texto en una porción de texto usaremos el comando FIND con los marcadores y BNDS.
Queremos buscar la t entre las columnas 3 y 6 y entre las líneas 10 y 12.
1.-Tecleamos el comando COLS, para saber las posición de las columnas
2.-Tecleamos el comando BNDS, para establecer el intervalo (de columnas) en el que buscar
3.-Establecemos dos marcadores. Uno en la línea 10 y otro en la línea 12.
4.-Tecleamos el comando F t .A .B
Veamoslo en nuestro editor:
Command ===> F 't' .A .B
=COLS> ----+----1---
=BNDS> < >
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
Command ===>
=COLS> ----+----1---
=BNDS> < >
.A Texto A
000011 Texto B
.B Texto C
000013 Texto D
miércoles, 25 de mayo de 2011
Comandos TSO vol.2
En este artículo continuamos con los comandos TSO, muy útiles tanto para codificar como para editar texto.
Para los que no lo hayan leído, podéis ver los comandos básicos en "Comandos TSO vol.1: Comandos del editor".
OCULTAR / MOSTRAR LINEAS
Ocultar líneas.
El comando para ocultar líneas es la letra 'X'.
Si tecleamos una X sobre la columna de la línea 11:
000010 Texto A
X00011 Texto B
000012 Texto C
000013 Texto D
Ocultaría la línea 11.
000010 Texto A
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000012 Texto C
000013 Texto D
Si tecleamos X2 sobre la columna de la línea 11:
000010 Texto A
X20011 Texto B
000012 Texto C
000013 Texto D
Ocultaría 2 líneas a partir de la linea 11 incluída.
000010 Texto A
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000013 Texto D
Ocultar bloques de líneas.
El comando para ocultar bloques de líneas es 'XX ... XX'.
Si tecleamos una XX ... XX sobre la columna de las líneas 11 y 12:
000010 Texto A
XX0011 Texto B
XX0012 Texto C
000013 Texto D
Ocultaría las líneas que haya enter el primer XX y el último (incluídas las líneas sobre las que hayamos escrito el XX).
000010 Texto A
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000013 Texto D
Mostar líneas.
Los comandos para mostrar líneas son las letras 'S / F / L'.
Veamos cada uno de ellos.
Comando F: Muesta la(s) primera(s) línea(s)
Si tecleamos una F sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
F - - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría la línea 11.
000010 Texto A
000011 Texto B
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000014 Texto E
Si tecleamos F2 sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
F2- - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría 2 líneas a partir de la linea 10 (líneas 11 y 12).
000010 Texto A
000011 Texto B
000012 Texto C
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000014 Texto E
Comando L: Muestra la(s) última(s) línea(s).
Tiene un análogo comportamiento a F, pero en vez de mostrar las primeras líneas muestra las últimas, veamos el ejemplo:
Si tecleamos L2 sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
L2- - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría 2 líneas a partir de la linea 10 (líneas 12 y 13).
000010 Texto A
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000012 Texto C
000013 Texto D
000014 Texto E
Por último tenemos el comando S: Muestra la(s) línea(s) más significativas de un bloque de líneas ocultas.
No vamos a exponer el funcionamiento del mismo. Si alguien tiene interés lo puede preguntar y se lo explicaremos.
OTROS COMANDOS
BNDS. Establece límites de trabajo.
El comando BNDS nos permite fijar los márgenes izquierdo y derecho.
Para poder trabajar con este comando escríbelo sobre la columna que indica el numero de línea BNDS
000010 Texto A
BNDS11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=BNDS> < >
000011 Texto B
000012 Texto C
000013 Texto D
El símbolo < indica la posición del margen izquierdo. Por defecto es la primera posición.
El símbolo > indica la posición del margen derecho. Por defecto es la última posición.
El objetivo del BOUNDS es limitar la acción de los comandos entre el margen izquierdo y el margen derecho.
Lo vemos en un ejemplo:
Si tuviésemos:
=BNDS> < >
M00010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B1
000011 Texto C1
000012 Texto D1
Sin embargo
Si tuviésemos:
=BNDS> < >
M00010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B
000011 Texto C
000012 Texto D
El 1 no se llevaría al resto de líneas ya que queda fuera de los márgenes establecidos por el BNDS.
COLS. Es un comando informativo que nos indica el número de columna.
Para poder trabajar con este comando escríbelo sobre la columna que indica el numero de línea COLS
000010 Texto A
COLS11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=COLS> ---+----1---+----2---+----3---+----4---+----5
000011 Texto B
000012 Texto C
000013 Texto D
MASK. Es un comando que nos permite definir la estrucutura de una linea.
Para poder trabajar con este comando escríbelo sobre la columna que indica el número de línea MASK
000010 Texto A
MASK11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=MASK>
000011 Texto B
000012 Texto C
000013 Texto D
La máscara por defecto es una línea en blanco. Cada vez que hagamos un insert de una nueva línea nos mostrará una línea en blanco.
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
''''''
000012 Texto C
000013 Texto D
Cambiamos la máscara:
000010 Texto A
=MASK> * *
000011 Texto B
000012 Texto C
000013 Texto D
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
'''''' * *
000012 Texto C
000013 Texto D
Nos puede ser útil en casos como añadir un párrafo de comentarios.
También dentro de este bloque podemos añadir el comando TABS que nos permite ver y cambiar la tabulación por defecto.
En este articulo no vamos a explica su fucionamiento, si alguien tiene interés lo puede preguntar y se lo explicaremos.
Con esto finalizamos este segundo volumen de comandos TSO.
Continuaremos explicando otros comandos, pero ahora ya desde la linea de comandos, en siguientes entregas.
Para los que no lo hayan leído, podéis ver los comandos básicos en "Comandos TSO vol.1: Comandos del editor".
OCULTAR / MOSTRAR LINEAS
Ocultar líneas.
El comando para ocultar líneas es la letra 'X'.
Si tecleamos una X sobre la columna de la línea 11:
000010 Texto A
X00011 Texto B
000012 Texto C
000013 Texto D
Ocultaría la línea 11.
000010 Texto A
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000012 Texto C
000013 Texto D
Si tecleamos X2 sobre la columna de la línea 11:
000010 Texto A
X20011 Texto B
000012 Texto C
000013 Texto D
Ocultaría 2 líneas a partir de la linea 11 incluída.
000010 Texto A
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000013 Texto D
Ocultar bloques de líneas.
El comando para ocultar bloques de líneas es 'XX ... XX'.
Si tecleamos una XX ... XX sobre la columna de las líneas 11 y 12:
000010 Texto A
XX0011 Texto B
XX0012 Texto C
000013 Texto D
Ocultaría las líneas que haya enter el primer XX y el último (incluídas las líneas sobre las que hayamos escrito el XX).
000010 Texto A
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000013 Texto D
Mostar líneas.
Los comandos para mostrar líneas son las letras 'S / F / L'.
Veamos cada uno de ellos.
Comando F: Muesta la(s) primera(s) línea(s)
Si tecleamos una F sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
F - - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría la línea 11.
000010 Texto A
000011 Texto B
- - - - - - - - - - - - - - - - - 2 Line(s) not Displayed
000014 Texto E
Si tecleamos F2 sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
F2- - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría 2 líneas a partir de la linea 10 (líneas 11 y 12).
000010 Texto A
000011 Texto B
000012 Texto C
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000014 Texto E
Comando L: Muestra la(s) última(s) línea(s).
Tiene un análogo comportamiento a F, pero en vez de mostrar las primeras líneas muestra las últimas, veamos el ejemplo:
Si tecleamos L2 sobre la línea que nos muestra las líneas ocultas:
000010 Texto A
L2- - - - - - - - - - - - - - - - 3 Line(s) not Displayed
000014 Texto E
Mostraría 2 líneas a partir de la linea 10 (líneas 12 y 13).
000010 Texto A
- - - - - - - - - - - - - - - - - 1 Line(s) not Displayed
000012 Texto C
000013 Texto D
000014 Texto E
Por último tenemos el comando S: Muestra la(s) línea(s) más significativas de un bloque de líneas ocultas.
No vamos a exponer el funcionamiento del mismo. Si alguien tiene interés lo puede preguntar y se lo explicaremos.
OTROS COMANDOS
BNDS. Establece límites de trabajo.
El comando BNDS nos permite fijar los márgenes izquierdo y derecho.
Para poder trabajar con este comando escríbelo sobre la columna que indica el numero de línea BNDS
000010 Texto A
BNDS11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=BNDS> < >
000011 Texto B
000012 Texto C
000013 Texto D
El símbolo < indica la posición del margen izquierdo. Por defecto es la primera posición.
El símbolo > indica la posición del margen derecho. Por defecto es la última posición.
El objetivo del BOUNDS es limitar la acción de los comandos entre el margen izquierdo y el margen derecho.
Lo vemos en un ejemplo:
Si tuviésemos:
=BNDS> < >
M00010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B1
000011 Texto C1
000012 Texto D1
Sin embargo
Si tuviésemos:
=BNDS> < >
M00010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B
000011 Texto C
000012 Texto D
El 1 no se llevaría al resto de líneas ya que queda fuera de los márgenes establecidos por el BNDS.
COLS. Es un comando informativo que nos indica el número de columna.
Para poder trabajar con este comando escríbelo sobre la columna que indica el numero de línea COLS
000010 Texto A
COLS11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=COLS> ---+----1---+----2---+----3---+----4---+----5
000011 Texto B
000012 Texto C
000013 Texto D
MASK. Es un comando que nos permite definir la estrucutura de una linea.
Para poder trabajar con este comando escríbelo sobre la columna que indica el número de línea MASK
000010 Texto A
MASK11 Texto B
000012 Texto C
000013 Texto D
Nos mostraría la siguiente ventana.
000010 Texto A
=MASK>
000011 Texto B
000012 Texto C
000013 Texto D
La máscara por defecto es una línea en blanco. Cada vez que hagamos un insert de una nueva línea nos mostrará una línea en blanco.
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
''''''
000012 Texto C
000013 Texto D
Cambiamos la máscara:
000010 Texto A
=MASK> * *
000011 Texto B
000012 Texto C
000013 Texto D
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
'''''' * *
000012 Texto C
000013 Texto D
Nos puede ser útil en casos como añadir un párrafo de comentarios.
También dentro de este bloque podemos añadir el comando TABS que nos permite ver y cambiar la tabulación por defecto.
En este articulo no vamos a explica su fucionamiento, si alguien tiene interés lo puede preguntar y se lo explicaremos.
Con esto finalizamos este segundo volumen de comandos TSO.
Continuaremos explicando otros comandos, pero ahora ya desde la linea de comandos, en siguientes entregas.
miércoles, 20 de abril de 2011
Comandos TSO vol.1: Comandos del editor
El editor de TSO cuenta con una serie de comandos que nos ayudarán a escribir nuestro código.
En este volumen veremos los comandos básicos con algunos ejemplos.
Supongamos el siguiente trozo de texto en el editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
El bloque de la izquierda (verde) nos indica el número de línea del texto.
El bloque de la derecha (amarillo) contiene el texto de cada línea.
Los comandos se teclearán sobre la columna de los números de línea.
INSERTAR / BORRAR / DUPLICAR LINEAS
Insertar líneas.
El comando para insertar líneas es la letra 'I'.
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
'''''' En esta sección amarilla escribiremos nuestro texto
000012 Texto C
000013 Texto D
Al pulsar INTRO quedaría:
000010 Texto A
000011 Texto B
000012 En esta sección amarilla escribiremos nuestro texto
000013 Texto C
000014 Texto D
Si en el texto inicial tecleamos I3 sobre la columna de la línea 11:
000010 Texto A
I30011 Texto B
000012 Texto C
000013 Texto D
Insertaría 3 líneas para poder escribir nuestro texto a continuación de la línea 11.
000010 Texto A
000011 Texto B
''''''
''''''
''''''
000012 Texto C
000013 Texto D
Borrar líneas.
El comando para borrar líneas es la letra 'D'.
Si tecleamos una D sobre la columna de la línea 11:
000010 Texto A
D00011 Texto B
000012 Texto C
000013 Texto D
Borraría la línea 11.
000010 Texto A
000012 Texto C
000013 Texto D
Si tecleamos D2 sobre la columna de la línea 11:
000010 Texto A
D20011 Texto B
000012 Texto C
000013 Texto D
Borraría 2 líneas a partir de la linea 11 incluída.
000010 Texto A
000013 Texto D
Borrar bloques de líneas.
El comando para borrar bloques de líneas es 'DD ... DD'.
Si tecleamos una DD ... DD sobre la columna de las líneas 11 y 12:
000010 Texto A
DD0011 Texto B
DD0012 Texto C
000013 Texto D
Borraría las líneas que haya enter el primer DD y el último (incluídas las líneas sobre las que hayamos escrito el DD).
000010 Texto A
000013 Texto D
Replicar líneas.
El comando para replicar líneas es la 'R'.
Si tecleamos una R sobre la columna de la línea 11:
000010 Texto A
R00011 Texto B
000012 Texto C
000013 Texto D
Replicaría la línea 11.
000010 Texto A
000011 Texto B
000012 Texto B
000013 Texto C
000014 Texto D
Si tecleamos R2 sobre la columna de la línea 11:
000010 Texto A
R20011 Texto B
000012 Texto C
000013 Texto D
Replicaría la línea 11 dos veces.
000010 Texto A
000011 Texto B
000012 Texto B
000013 Texto B
000014 Texto C
000015 Texto D
Replicar bloques de líneas.
El comando para replicar bloques de líneas es 'RR ... RR'.
Si tecleamos una RR ... RR sobre la columna de las líneas 11 y 12:
000010 Texto A
RR0011 Texto B
RR0012 Texto C
000013 Texto D
Replicaría las líneas que hay entre el primer RR y el último (ambas incluídas).
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto C
000015 Texto D
MOVER / COPIAR LINEAS
Para mover y/o copiar líneas entran dos comandos en juego: el que selecciona la línea a copiar / mover y el que nos indica el lugar donde se va a copiar o mover.
Para la primera parte tenemos comandos C->copiar línea y M->mover línea.
Para la segunda parte tenemos comandos A->después de, B->antes de y O->sobre.
Dado el siguiente código en nuestro editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Copiar líneas
Si queremos copiar la línea de texto "Texto B" entre las líneas de texto "Texto C" y "Texto D" podríamos hacer:
000010 Texto A
C00011 Texto B
000012 Texto C
B00013 Texto D
O bien
000010 Texto A
C00011 Texto B
A00012 Texto C
000013 Texto D
En el primer caso nos indica que vamos a copiar la línea antes de la línea de texto "Texto D". En el segundo caso vamos a copiar la línea después de la línea de texto "Texto C". En ambos casos el resultado sería:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto D
Mover líneas
Si en vez de copiar la línea, la quisiésemos mover podríamos hacer:
000010 Texto A
M00011 Texto B
000012 Texto C
B00013 Texto D
O bien
000010 Texto A
M00011 Texto B
A00012 Texto C
000013 Texto D
En ambos casos el resultado sería:
000010 Texto A
000011 Texto C
000012 Texto B
000013 Texto D
Si quisiésemos copiar una linea varias veces podríamos hacer:
000010 Texto A
C00011 Texto B
000012 Texto C
B20013 Texto D
O bien
000010 Texto A
C00011 Texto B
A20012 Texto C
000013 Texto D
El resultado sería:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto B
000015 Texto D
Mover / Copiar bloques de líneas
Para copiar bloques usaremos el comando CC ... CC. Y para mover bloques MM ... MM.
En ambos casos siguen siendo válidos (y necesarios) los comandos A (después de) y B (antes de).
Copiar un bloque.
CC0010 Texto A
CC0011 Texto B
000012 Texto C
B00013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto B
000014 Texto C
000012 Texto A
000013 Texto B
000015 Texto D
Mover un bloque.
MM0010 Texto A
MM0011 Texto B
000012 Texto C
A00013 Texto D
Nos daría el siguiente resultado:
000010 Texto C
000011 Texto D
000012 Texto A
000013 Texto B
Mover / Copiar líneas sobre ...
Hemos dejado para el final el comando O, por tener un comportamiento distinto a los comandos A y B.
Veamos funcionar este comando en un ejemplo.
000010 Texto A
C00011 Texto B1
O00012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto B1
000012 Texto C1
000013 Texto D
Del mismo modo si tuviésemos:
000010 Texto A
M00011 Texto B1
O00012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto C1
000012 Texto D
NOTA: Como se puede observar, este último comando actúa sobre aquellas posiciones que están informadas a blancos. Sobre las que están informadas no hace nada.
Así la letra C (de la línea de destino) permanece, y le añade un 1 cuyo origen está en la linea inicial.
Al igual que A y B, el comando O admite On, donde n es un número.
Si tuviésemos:
C00010 Texto A1
O30011 Texto B
000012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
00010 Texto A1
000011 Texto B1
000012 Texto C1
000013 Texto D1
También adimite bloques. Por ejemplo si tuviésemos:
M000010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B1
000011 Texto C1
000012 Texto D1
Esto es aplicable también al comando de copiar ('C') y también a copiar y mover con bloques ('CC...CC' y 'MM...MM').
DESPLAZAR TEXTO SOBRE UNA LINEA
Los comandos para manipular la posición del texto en una línea son '(' y '<' para desplazamiento a la izquierda, ')' y '> para desplazamiento a la derecha.
Pero veamos cada unos de los comandos en detalle con ejemplos:
Dado el siguiente código en nuestro editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Si tuviésemos la siguiente situación:
000010 Texto A
(00011 Texto B
000012 Texto C
000013 Texto D
Desplazaría el texto de la línea 2 posiciones a la izquierda.
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Análogo resultado tendremos con el siguiente ejemplo:
000010 Texto A
<00011 Texto B
000012 Texto C
000013 Texto D
Sin embargo estos comandos tienen diferencias. Veamos el siguiente ejemplo:
<00010 Texto A
(00011 Texto B
<00012 Texto C
(00013 Texto D
<00014 Texto E
(00015 Texto F
El resultado sería:
000010 Texto A
000011 Texto B
==ERR> Texto C
000013 xto D
000014 Texto E
000015 Texto F
¿Qué ha sucedido?
El comando ( elimina dos posiciones de texto desde la posición 1.
El comando < elimina dos espacios desde la posición 1.
He ahí que la línea 000012 al intentar desplazar el texto con el comando < nos haya dado un error (las dos primeras posiciones son distintas de espacio).
Otra diferencia entre ambos comandos la vemos en las líneas 000014 y 000015
El comando ( elimina dos posiciones de texto desplazando toda la línea.
El comando < elimina dos espacios desplazando sólo el primer trozo de texto que esté separado por más de dos espacios.
Un compartamiento análogo ocurriría entre > y ). Veámoslo en un ejemplo:
Supongamos que estamos editando un fichero de 13 posiciones.
=COLS> ----+----1---
>00010 Texto A
)00011 Texto B
>00012 Texto C
)00013 Texto D
>00014 Texto E
>00015 Texto G
)00016 Texto F
El resultado sería:
=COLS> ----+----1---
==ERR> Texto A
000011 Texto
000012 Texto C
000013 Texto D
000014 Texto E
000015 Texto G
000015 Texto F
Vemos que el comportamiento es el esperado, pero en sentido contrario. En vez de a la izquierda a la derecha.
El único compartamiento que nos puede sorprender es el de la línea 000014. En este caso lo que ha ocurrido con el comando >, al tratar de desplazar el primer trozo de texto que esté separado por más de dos espacios, es que el primer trozo de texto es "Texto" pues el resto de la línea ("E") estaba separado de "Texto" dos espacios. Al desplazar un espacio "Texto", ese primer trozo ha dejado de ser "Texto" para ser "Texto E". Y por tanto al desplazar el segundo espacio ha desplazado "Texto E".
Además cada uno de estos comandos pueden ser seguidos de un número < n ó (n ó >n ó )n donde n es un número.
También es válido para bloques: << ... << n ó (( ... ((n ó >> ... >>n ó )) ... ))n donde n es un número (si no viene especificado por defecto es 2).
Veámoslo en un ejemplo:
=COLS> ----+----1----+----2
))0010 Texto A
000011 Texto B
))5012 Texto C
<<0013 Texto D
<<3014 Texto E
000015 Texto G
000016 Texto F
Veamos el resultado:
=COLS> ----+----1----+----2
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
000014 Texto E
000015 Texto G
000016 Texto F
En este volumen veremos los comandos básicos con algunos ejemplos.
Supongamos el siguiente trozo de texto en el editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
El bloque de la izquierda (verde) nos indica el número de línea del texto.
El bloque de la derecha (amarillo) contiene el texto de cada línea.
Los comandos se teclearán sobre la columna de los números de línea.
INSERTAR / BORRAR / DUPLICAR LINEAS
Insertar líneas.
El comando para insertar líneas es la letra 'I'.
Si tecleamos una I sobre la columna de la línea 11:
000010 Texto A
I00011 Texto B
000012 Texto C
000013 Texto D
Insertaría 1 línea para poder escribir nuestro texto a continuación de nuestra línea 11.
000010 Texto A
000011 Texto B
'''''' En esta sección amarilla escribiremos nuestro texto
000012 Texto C
000013 Texto D
Al pulsar INTRO quedaría:
000010 Texto A
000011 Texto B
000012 En esta sección amarilla escribiremos nuestro texto
000013 Texto C
000014 Texto D
Si en el texto inicial tecleamos I3 sobre la columna de la línea 11:
000010 Texto A
I30011 Texto B
000012 Texto C
000013 Texto D
Insertaría 3 líneas para poder escribir nuestro texto a continuación de la línea 11.
000010 Texto A
000011 Texto B
''''''
''''''
''''''
000012 Texto C
000013 Texto D
Borrar líneas.
El comando para borrar líneas es la letra 'D'.
Si tecleamos una D sobre la columna de la línea 11:
000010 Texto A
D00011 Texto B
000012 Texto C
000013 Texto D
Borraría la línea 11.
000010 Texto A
000012 Texto C
000013 Texto D
Si tecleamos D2 sobre la columna de la línea 11:
000010 Texto A
D20011 Texto B
000012 Texto C
000013 Texto D
Borraría 2 líneas a partir de la linea 11 incluída.
000010 Texto A
000013 Texto D
Borrar bloques de líneas.
El comando para borrar bloques de líneas es 'DD ... DD'.
Si tecleamos una DD ... DD sobre la columna de las líneas 11 y 12:
000010 Texto A
DD0011 Texto B
DD0012 Texto C
000013 Texto D
Borraría las líneas que haya enter el primer DD y el último (incluídas las líneas sobre las que hayamos escrito el DD).
000010 Texto A
000013 Texto D
Replicar líneas.
El comando para replicar líneas es la 'R'.
Si tecleamos una R sobre la columna de la línea 11:
000010 Texto A
R00011 Texto B
000012 Texto C
000013 Texto D
Replicaría la línea 11.
000010 Texto A
000011 Texto B
000012 Texto B
000013 Texto C
000014 Texto D
Si tecleamos R2 sobre la columna de la línea 11:
000010 Texto A
R20011 Texto B
000012 Texto C
000013 Texto D
Replicaría la línea 11 dos veces.
000010 Texto A
000011 Texto B
000012 Texto B
000013 Texto B
000014 Texto C
000015 Texto D
Replicar bloques de líneas.
El comando para replicar bloques de líneas es 'RR ... RR'.
Si tecleamos una RR ... RR sobre la columna de las líneas 11 y 12:
000010 Texto A
RR0011 Texto B
RR0012 Texto C
000013 Texto D
Replicaría las líneas que hay entre el primer RR y el último (ambas incluídas).
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto C
000015 Texto D
MOVER / COPIAR LINEAS
Para mover y/o copiar líneas entran dos comandos en juego: el que selecciona la línea a copiar / mover y el que nos indica el lugar donde se va a copiar o mover.
Para la primera parte tenemos comandos C->copiar línea y M->mover línea.
Para la segunda parte tenemos comandos A->después de, B->antes de y O->sobre.
Dado el siguiente código en nuestro editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Copiar líneas
Si queremos copiar la línea de texto "Texto B" entre las líneas de texto "Texto C" y "Texto D" podríamos hacer:
000010 Texto A
C00011 Texto B
000012 Texto C
B00013 Texto D
O bien
000010 Texto A
C00011 Texto B
A00012 Texto C
000013 Texto D
En el primer caso nos indica que vamos a copiar la línea antes de la línea de texto "Texto D". En el segundo caso vamos a copiar la línea después de la línea de texto "Texto C". En ambos casos el resultado sería:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto D
Mover líneas
Si en vez de copiar la línea, la quisiésemos mover podríamos hacer:
000010 Texto A
M00011 Texto B
000012 Texto C
B00013 Texto D
O bien
000010 Texto A
M00011 Texto B
A00012 Texto C
000013 Texto D
En ambos casos el resultado sería:
000010 Texto A
000011 Texto C
000012 Texto B
000013 Texto D
Si quisiésemos copiar una linea varias veces podríamos hacer:
000010 Texto A
C00011 Texto B
000012 Texto C
B20013 Texto D
O bien
000010 Texto A
C00011 Texto B
A20012 Texto C
000013 Texto D
El resultado sería:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto B
000014 Texto B
000015 Texto D
Mover / Copiar bloques de líneas
Para copiar bloques usaremos el comando CC ... CC. Y para mover bloques MM ... MM.
En ambos casos siguen siendo válidos (y necesarios) los comandos A (después de) y B (antes de).
Copiar un bloque.
CC0010 Texto A
CC0011 Texto B
000012 Texto C
B00013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto B
000014 Texto C
000012 Texto A
000013 Texto B
000015 Texto D
Mover un bloque.
MM0010 Texto A
MM0011 Texto B
000012 Texto C
A00013 Texto D
Nos daría el siguiente resultado:
000010 Texto C
000011 Texto D
000012 Texto A
000013 Texto B
Mover / Copiar líneas sobre ...
Hemos dejado para el final el comando O, por tener un comportamiento distinto a los comandos A y B.
Veamos funcionar este comando en un ejemplo.
000010 Texto A
C00011 Texto B1
O00012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto B1
000012 Texto C1
000013 Texto D
Del mismo modo si tuviésemos:
000010 Texto A
M00011 Texto B1
O00012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
000010 Texto A
000011 Texto C1
000012 Texto D
NOTA: Como se puede observar, este último comando actúa sobre aquellas posiciones que están informadas a blancos. Sobre las que están informadas no hace nada.
Así la letra C (de la línea de destino) permanece, y le añade un 1 cuyo origen está en la linea inicial.
Al igual que A y B, el comando O admite On, donde n es un número.
Si tuviésemos:
C00010 Texto A1
O30011 Texto B
000012 Texto C
000013 Texto D
Nos daría el siguiente resultado:
00010 Texto A1
000011 Texto B1
000012 Texto C1
000013 Texto D1
También adimite bloques. Por ejemplo si tuviésemos:
M000010 Texto A1
OO0011 Texto B
000012 Texto C
OO0013 Texto D
Nos daría el siguiente resultado:
000010 Texto B1
000011 Texto C1
000012 Texto D1
Esto es aplicable también al comando de copiar ('C') y también a copiar y mover con bloques ('CC...CC' y 'MM...MM').
DESPLAZAR TEXTO SOBRE UNA LINEA
Los comandos para manipular la posición del texto en una línea son '(' y '<' para desplazamiento a la izquierda, ')' y '> para desplazamiento a la derecha.
Pero veamos cada unos de los comandos en detalle con ejemplos:
Dado el siguiente código en nuestro editor:
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Si tuviésemos la siguiente situación:
000010 Texto A
(00011 Texto B
000012 Texto C
000013 Texto D
Desplazaría el texto de la línea 2 posiciones a la izquierda.
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
Análogo resultado tendremos con el siguiente ejemplo:
000010 Texto A
<00011 Texto B
000012 Texto C
000013 Texto D
Sin embargo estos comandos tienen diferencias. Veamos el siguiente ejemplo:
<00010 Texto A
(00011 Texto B
<00012 Texto C
(00013 Texto D
<00014 Texto E
(00015 Texto F
El resultado sería:
000010 Texto A
000011 Texto B
==ERR> Texto C
000013 xto D
000014 Texto E
000015 Texto F
¿Qué ha sucedido?
El comando ( elimina dos posiciones de texto desde la posición 1.
El comando < elimina dos espacios desde la posición 1.
He ahí que la línea 000012 al intentar desplazar el texto con el comando < nos haya dado un error (las dos primeras posiciones son distintas de espacio).
Otra diferencia entre ambos comandos la vemos en las líneas 000014 y 000015
El comando ( elimina dos posiciones de texto desplazando toda la línea.
El comando < elimina dos espacios desplazando sólo el primer trozo de texto que esté separado por más de dos espacios.
Un compartamiento análogo ocurriría entre > y ). Veámoslo en un ejemplo:
Supongamos que estamos editando un fichero de 13 posiciones.
=COLS> ----+----1---
>00010 Texto A
)00011 Texto B
>00012 Texto C
)00013 Texto D
>00014 Texto E
>00015 Texto G
)00016 Texto F
El resultado sería:
=COLS> ----+----1---
==ERR> Texto A
000011 Texto
000012 Texto C
000013 Texto D
000014 Texto E
000015 Texto G
000015 Texto F
Vemos que el comportamiento es el esperado, pero en sentido contrario. En vez de a la izquierda a la derecha.
El único compartamiento que nos puede sorprender es el de la línea 000014. En este caso lo que ha ocurrido con el comando >, al tratar de desplazar el primer trozo de texto que esté separado por más de dos espacios, es que el primer trozo de texto es "Texto" pues el resto de la línea ("E") estaba separado de "Texto" dos espacios. Al desplazar un espacio "Texto", ese primer trozo ha dejado de ser "Texto" para ser "Texto E". Y por tanto al desplazar el segundo espacio ha desplazado "Texto E".
Además cada uno de estos comandos pueden ser seguidos de un número < n ó (n ó >n ó )n donde n es un número.
También es válido para bloques: << ... << n ó (( ... ((n ó >> ... >>n ó )) ... ))n donde n es un número (si no viene especificado por defecto es 2).
Veámoslo en un ejemplo:
=COLS> ----+----1----+----2
))0010 Texto A
000011 Texto B
))5012 Texto C
<<0013 Texto D
<<3014 Texto E
000015 Texto G
000016 Texto F
Veamos el resultado:
=COLS> ----+----1----+----2
000010 Texto A
000011 Texto B
000012 Texto C
000013 Texto D
000014 Texto E
000015 Texto G
000016 Texto F
lunes, 11 de abril de 2011
CONSULTAS SQL. PARTE I
Vamos a presentar una serie de artículos para mostar las distintas posibilidades que puede ofrecer el SQL.
En esta primera parte nos centraremos en las JOINs de tablas.
LEFT OUTER JOIN
Supongamos la siguiente situación, una lista de alumnos que no estén matriculados en alguna asignatura obligatoria.
Para ello tenemos las entidades ALUMNO (alumnos matriculados en una universidad), ASIGNATOBL (lista de asignaturas obligatorias, existente en los grados) y ASIGNATOPC (lista de asignaturas opcionales, existente en los grados).
Entidad ALUMNO.
idPersona | idAsignatura | idCurso | idGrado
P1 OB1 C1 G1
P1 OB2 C1 G1
P2 OP1 C1 G1
P3 OP2 C1 G1
P4 OP1 C1 G1
P4 OB2 C1 G1
P5 OB1 C1 G1
P6 OP2 C1 G1
Donde la clave primaria es idPerona, idAsignatura, idCurso, idGrado.
Entidad ASIGNATOBL
idAsignatura| idCurso | idGrado | Nombre | Duración
OB1 C1 G1 ASIGOB1 S
OB2 C1 G1 ASIGOB2 S
OB3 C1 G1 ASIGOB3 S
Donde la clave primaria es idAsignatura, idCurso, idGrado.
Entidad ASIGNATOPC
idAsignatura| idCurso | idGrado | Nombre | Duración
OP1 C1 G1 ASIGOP1 S
OP2 C1 G1 ASIGOP2 S
OP3 C1 G1 ASIGOP3 S
Donde la clave primaria es idAsignatura, idCurso, idGrado.
La Consulta que haríamos:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esto crea una nueva tabla resultante, que tendrá tantos registros como la entidad ALUMNO. El campo idPersona proviene de la tabla ALUMNOS y por tanto vendrá siempre informado a no NULOS. Los campos Nombre y Duración provienen de la tabla ASIGNATOBL en el caso de que coincidan las claves vendrán informados con valor en otro caso vendrán informados a NULOS.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P2 NULL NULL
P3 NULL NULL
P4 NULL NULL
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
P7 NULL NULL
Vamos a comentar un par de cosas sobre esta consulta:
El bloque sobre el que estamos uniendo ambas entidades(tablas)
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
El bloque sobre el que estamos definiendo el tipo de interacción de las tablas:
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
Aquí también es importante decir que cuando hacemos un "A LEFT OUTER JOIN B", las diferentes claves de interacción de la tablas (A y B), tienen que estar todas ellas en la tabla A, pudiendo no estar obligatoriamente todas en la tabla B. Es decir, A contiene B.
Podríamos añadir una sentencia WHERE [WHERE B.Nombre IS NULL].
En este punto debemos hacer una pausa. La sentencia WHERE es una condición de filtrado sobre la tabla temporal resultante de unir las tablas A y B. Es decir:
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
AND B.Nombre IS NULL
Es distinto a:
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
WHERE B.Nombre IS NULL
En el primer caso [AND B.Nombre IS NULL]. Usaría una condicion más para la creación de la nueva tabla temporal (en este caso no haríamos ningún filtro pues en la tabla B no hay valores nulos sobre la columna Nombre).
En el sengundo caso [WHERE B.Nombre IS NULL]. Usaría la condición para filtrar el resultado de la nueva tabla temporal.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P2 NULL NULL
P3 NULL NULL
P4 NULL NULL
P7 NULL NULL
INNER JOIN(modo explícito)
Supongamos la siguiente situación, nos piden la información de qué alumnos están matriculados en alguna asignatura obligatoria, e información sobre dicha asignatura.
La Consulta que haríamos:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
INNER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esto crea una nueva tabla resultante, que tendrá aquellos registros en los que las claves de ambas tablas coincidan. A diferencia del anterior caso los campos idPersona, Nombre y Duración vendrán informado a no NULOS.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
Este sería un caso particular del LEFT OUTER JOIN. Podemos representar el INNER JOIN con la siguiente consulta creada con LEFT OUTER JOIN:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
WHERE B.Nombre IS NOT NULL
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
INNER JOIN(modo implícito)
Veamos la INNER JOIN anterior expresada de otra forma:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
,ASIGNATOBL B
WHERE A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Es otra manera de expresar la inner join de dos tablas (tal vez la más conocida, la que primero que se estudia).
EL resultado es el mismo:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
RIGHT OUTER JOIN
Es un caso particular del LEFT OUTER JOIN. Mientras que en la LEFT, A contiene a B, en la RIGHT B contiene a A.
Veámoslo con un ejemplo:
Cuando explicábamos la LEFT OUTER JOIN, en el caso que proponíamos ("obtener la información de qué alumnos están matriculados en alguna asignatura obligatoria, e información sobre dicha asignatura"), llegamos a la siguiente consulta:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esta consulta se puede expresar con la RIGHT OUTER JOIN obteniendo el mismo resultado. La consulta sería:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ASIGNATOBL A
RIGHT OUTER JOIN
ALUMNO B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
FULL OUTER JOIN
Para este ultimo caso vamos a hacer un estudio entre dos alumnos. En este estudio nos piden información sobre qué asignaturas comparten, y cuales no.
Para esto primero seleccionamos las asignaturas en las que están matriculados cada uno de ellos. Haremos las siguientes consultas:
SELECT idAsinatura, B.Nombre, B.Duracion
FROM ALUMNO
WHERE A.idPersona = 'P5'
Análogamente hacemos la misma consulta para el segundo alumno:
SELECT idAsinatura, B.Nombre, B.Duracion
FROM ALUMNO
WHERE A.idPersona = 'P6'
Para extraer la información deseada hacemos una FULL OUTER JOIN entre ambas tablas temporales creadas. Nuestra consulta sería:
SELECT A.idAsignatura AS ASIGNP5, B.idAsignatura AS ASIGNP6
FROM (
SELECT idAsignatura
FROM ALUMNO
WHERE idPersona = 'P5') A
FULL OUTER JOIN (
SELECT idAsignatura
FROM ALUMNO
WHERE idPersona = 'P6') B
ON A.idAsignatura = B.idAsignatura
NOTA: En esta consulta hemos introducido un nuevo concepto de SELECT anidadas, que explicaremos en un artículo posterior. Quedémonos con la idea de que estamos haciendo una FULL OUTER JOIN sobre dos tablas, tablas temporales que tienen su raiz en una SELECT.
Esta consulta creará una nueva tabla que tendrá tantos registros como claves dierentes existan entre las dos tablas usadas para crear el FULL OUTER JOIN. Así nuestra nueva tabla temporal, será la siguiente:
ASIGNP5 | ASIGNP6
NULL OP2
OB1 NULL
Esta tabla sería la base para nuestro estudio pedido:
Si añadiésemos una sentencia WHERE [WHERE ASIGNP5 IS NOT NULL AND ASIGNP6 IS NOT NULL ] tendríamos la lista de las asignaturas en las que ambos están matriculados. En este caso la consulta sería vacía (no comparten las asiganturas en las que están matriculados).
NOTA: La sentencia WHERE tiene el mismo comportamiento que explicamos anteriormente con la LEFT OUTER JOIN.
Si añadiésemos una sentencia WHERE [WHERE ASIGNP5 IS NOT NULL] tendriamos la lista de las asignaturas en las que está matriculado el alumno P5 pero no el alumno P6. En este caso la consulta nos devolvería la asignatura OB1.
Si añadiésemos una sentencia WHERE [WHERE ASIGNP6 IS NOT NULL] tendriamos la lista de las asignaturas en las que está matriculado el alumno P6 pero no el alumno P5. En este caso la consulta nos devolvería la asignatura OP2.
Hasta aquí hemos hecho un breve repaso de los maneras más frecuentes que nos podemos encontrar a la hora de relacionar dos tablas en una consulta SQL. Espero que os sirva de ayuda y, si teneis alguna duda, no dudéis en preguntarla.
En esta primera parte nos centraremos en las JOINs de tablas.
LEFT OUTER JOIN
Supongamos la siguiente situación, una lista de alumnos que no estén matriculados en alguna asignatura obligatoria.
Para ello tenemos las entidades ALUMNO (alumnos matriculados en una universidad), ASIGNATOBL (lista de asignaturas obligatorias, existente en los grados) y ASIGNATOPC (lista de asignaturas opcionales, existente en los grados).
Entidad ALUMNO.
idPersona | idAsignatura | idCurso | idGrado
P1 OB1 C1 G1
P1 OB2 C1 G1
P2 OP1 C1 G1
P3 OP2 C1 G1
P4 OP1 C1 G1
P4 OB2 C1 G1
P5 OB1 C1 G1
P6 OP2 C1 G1
Donde la clave primaria es idPerona, idAsignatura, idCurso, idGrado.
Entidad ASIGNATOBL
idAsignatura| idCurso | idGrado | Nombre | Duración
OB1 C1 G1 ASIGOB1 S
OB2 C1 G1 ASIGOB2 S
OB3 C1 G1 ASIGOB3 S
Donde la clave primaria es idAsignatura, idCurso, idGrado.
Entidad ASIGNATOPC
idAsignatura| idCurso | idGrado | Nombre | Duración
OP1 C1 G1 ASIGOP1 S
OP2 C1 G1 ASIGOP2 S
OP3 C1 G1 ASIGOP3 S
Donde la clave primaria es idAsignatura, idCurso, idGrado.
La Consulta que haríamos:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esto crea una nueva tabla resultante, que tendrá tantos registros como la entidad ALUMNO. El campo idPersona proviene de la tabla ALUMNOS y por tanto vendrá siempre informado a no NULOS. Los campos Nombre y Duración provienen de la tabla ASIGNATOBL en el caso de que coincidan las claves vendrán informados con valor en otro caso vendrán informados a NULOS.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P2 NULL NULL
P3 NULL NULL
P4 NULL NULL
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
P7 NULL NULL
Vamos a comentar un par de cosas sobre esta consulta:
El bloque sobre el que estamos uniendo ambas entidades(tablas)
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
El bloque sobre el que estamos definiendo el tipo de interacción de las tablas:
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
Aquí también es importante decir que cuando hacemos un "A LEFT OUTER JOIN B", las diferentes claves de interacción de la tablas (A y B), tienen que estar todas ellas en la tabla A, pudiendo no estar obligatoriamente todas en la tabla B. Es decir, A contiene B.
Podríamos añadir una sentencia WHERE [WHERE B.Nombre IS NULL].
En este punto debemos hacer una pausa. La sentencia WHERE es una condición de filtrado sobre la tabla temporal resultante de unir las tablas A y B. Es decir:
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
AND B.Nombre IS NULL
Es distinto a:
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
WHERE B.Nombre IS NULL
En el primer caso [AND B.Nombre IS NULL]. Usaría una condicion más para la creación de la nueva tabla temporal (en este caso no haríamos ningún filtro pues en la tabla B no hay valores nulos sobre la columna Nombre).
En el sengundo caso [WHERE B.Nombre IS NULL]. Usaría la condición para filtrar el resultado de la nueva tabla temporal.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P2 NULL NULL
P3 NULL NULL
P4 NULL NULL
P7 NULL NULL
INNER JOIN(modo explícito)
Supongamos la siguiente situación, nos piden la información de qué alumnos están matriculados en alguna asignatura obligatoria, e información sobre dicha asignatura.
La Consulta que haríamos:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
INNER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esto crea una nueva tabla resultante, que tendrá aquellos registros en los que las claves de ambas tablas coincidan. A diferencia del anterior caso los campos idPersona, Nombre y Duración vendrán informado a no NULOS.
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
Este sería un caso particular del LEFT OUTER JOIN. Podemos representar el INNER JOIN con la siguiente consulta creada con LEFT OUTER JOIN:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
WHERE B.Nombre IS NOT NULL
El resultado de la consulta sería:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
INNER JOIN(modo implícito)
Veamos la INNER JOIN anterior expresada de otra forma:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
,ASIGNATOBL B
WHERE A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Es otra manera de expresar la inner join de dos tablas (tal vez la más conocida, la que primero que se estudia).
EL resultado es el mismo:
idPersona | Nombre | Duración
P1 ASIGOB1 S
P1 ASIGOB2 S
P4 ASIGOB2 S
P5 ASIGOB1 S
P6 ASIGOB2 S
RIGHT OUTER JOIN
Es un caso particular del LEFT OUTER JOIN. Mientras que en la LEFT, A contiene a B, en la RIGHT B contiene a A.
Veámoslo con un ejemplo:
Cuando explicábamos la LEFT OUTER JOIN, en el caso que proponíamos ("obtener la información de qué alumnos están matriculados en alguna asignatura obligatoria, e información sobre dicha asignatura"), llegamos a la siguiente consulta:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ALUMNO A
LEFT OUTER JOIN
ASIGNATOBL B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
Esta consulta se puede expresar con la RIGHT OUTER JOIN obteniendo el mismo resultado. La consulta sería:
SELECT A.idPersona, B.Nombre, B.Duracion
FROM ASIGNATOBL A
RIGHT OUTER JOIN
ALUMNO B
ON A.idAsignatura = B.idAsinatura
AND A.idCurso = B.idCurso
AND A.idGrado = B.idGrado
FULL OUTER JOIN
Para este ultimo caso vamos a hacer un estudio entre dos alumnos. En este estudio nos piden información sobre qué asignaturas comparten, y cuales no.
Para esto primero seleccionamos las asignaturas en las que están matriculados cada uno de ellos. Haremos las siguientes consultas:
SELECT idAsinatura, B.Nombre, B.Duracion
FROM ALUMNO
WHERE A.idPersona = 'P5'
Análogamente hacemos la misma consulta para el segundo alumno:
SELECT idAsinatura, B.Nombre, B.Duracion
FROM ALUMNO
WHERE A.idPersona = 'P6'
Para extraer la información deseada hacemos una FULL OUTER JOIN entre ambas tablas temporales creadas. Nuestra consulta sería:
SELECT A.idAsignatura AS ASIGNP5, B.idAsignatura AS ASIGNP6
FROM (
SELECT idAsignatura
FROM ALUMNO
WHERE idPersona = 'P5') A
FULL OUTER JOIN (
SELECT idAsignatura
FROM ALUMNO
WHERE idPersona = 'P6') B
ON A.idAsignatura = B.idAsignatura
NOTA: En esta consulta hemos introducido un nuevo concepto de SELECT anidadas, que explicaremos en un artículo posterior. Quedémonos con la idea de que estamos haciendo una FULL OUTER JOIN sobre dos tablas, tablas temporales que tienen su raiz en una SELECT.
Esta consulta creará una nueva tabla que tendrá tantos registros como claves dierentes existan entre las dos tablas usadas para crear el FULL OUTER JOIN. Así nuestra nueva tabla temporal, será la siguiente:
ASIGNP5 | ASIGNP6
NULL OP2
OB1 NULL
Esta tabla sería la base para nuestro estudio pedido:
Si añadiésemos una sentencia WHERE [WHERE ASIGNP5 IS NOT NULL AND ASIGNP6 IS NOT NULL ] tendríamos la lista de las asignaturas en las que ambos están matriculados. En este caso la consulta sería vacía (no comparten las asiganturas en las que están matriculados).
NOTA: La sentencia WHERE tiene el mismo comportamiento que explicamos anteriormente con la LEFT OUTER JOIN.
Si añadiésemos una sentencia WHERE [WHERE ASIGNP5 IS NOT NULL] tendriamos la lista de las asignaturas en las que está matriculado el alumno P5 pero no el alumno P6. En este caso la consulta nos devolvería la asignatura OB1.
Si añadiésemos una sentencia WHERE [WHERE ASIGNP6 IS NOT NULL] tendriamos la lista de las asignaturas en las que está matriculado el alumno P6 pero no el alumno P5. En este caso la consulta nos devolvería la asignatura OP2.
Hasta aquí hemos hecho un breve repaso de los maneras más frecuentes que nos podemos encontrar a la hora de relacionar dos tablas en una consulta SQL. Espero que os sirva de ayuda y, si teneis alguna duda, no dudéis en preguntarla.
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.
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.
Labels:
cruce,
easytrieve,
Fichero,
JCL,
pepegan
lunes, 14 de febrero de 2011
Sentencia SORT en un programa COBOL
Hemos visto en otros artículos como hacer un SORT en un JCL. En este artículo veremos como hacerlo en un programa cobol.
¿Utilidad? Depende. Lo cierto es que pudiendo hacerlo por JCL, no tiene caso hacerlo en un programa. Pero quién sabe! Tal vez alguno de los lectores puedan darnos una idea de su uso práctico : D
SORT:
La sentencia SORT en cobol sirve para ordenar registros por un campo clave que le indiquemos. Podremos elegir varias claves y definir si el orden será ascendente o descendente.
Para el ejemplo, hemos creado un fichero temporal en nuestro programa que utilizaremos para generar en él la información ordenada. Como registros a ordenar, utilizaremos una tabla interna, de tal forma que no necesitaremos utilizar ficheros en ningún momento.
La información ordenada se cargará desde el fichero temporal al registro de salida, que podría utilizarse a lo largo de la ejecución.
Nosotros nos pararemos cuando tengamos nuestra información ordenada, y la "displayaremos" mostrándola por SYSOUT.
IDENTIFICATION DIVISION.
PROGRAM-ID. PRGSORT.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
* Fichero temporal donde guardaremos la información ordenada
SELECT TABLA-SORT ASSIGN TO DISK "SORTWORK".
*
DATA DIVISION.
FILE SECTION.
* Definición del fichero temporal
SD TABLA-SORT
DATA RECORD IS ELEMENTO-SORT.
01 ELEMENTO-SORT.
05 SORT-CLAVE1 PIC X.
05 SORT-CLAVE2 PIC X(3).
05 SORT-CAMPO PIC X(10).
05 SORT-INDICADOR PIC X.
*
WORKING-STORAGE SECTION.
* Formato del registro de salida
01 VARIABLES.
05 WA-REGISTRO.
10 WA-SORT-CLAVE1 PIC X.
10 WA-SORT-CLAVE2 PIC X(3).
10 WA-SORT-CAMPO PIC X(10).
10 WA-SORT-INDICADOR PIC X.
* Switches que utilizaremos en los bucles
01 SWITCHES.
05 SW-FIN-TABLA-SORT PIC X(1).
88 SI-FIN-TABLA-SORT VALUE 'S'.
88 NO-FIN-TABLA-SORT VALUE 'N'.
* Tabla interna con los datos a ordenar
01 TABLA.
05 WT-TBL-LISTA.
10 PIC X(15) VALUE 'F216CAMPO02802S'.
10 PIC X(15) VALUE 'M144CAMPO17114N'.
10 PIC X(15) VALUE 'Q651CAMPO24536S'.
10 PIC X(15) VALUE 'F217CAMPO03312N'.
10 PIC X(15) VALUE 'T487CAMPO44914S'.
10 PIC X(15) VALUE 'O372CAMPO52113N'.
10 PIC X(15) VALUE 'F457CAMPO61224N'.
10 PIC X(15) VALUE 'L547CAMPO73985N'.
10 PIC X(15) VALUE 'L354CAMPO89173N'.
10 PIC X(15) VALUE 'W516CAMPO92815N'.
05 REDEFINES WT-TBL-LISTA.
10 WT-TBL-ELEMENTO OCCURS 15
INDEXED BY WI-ELEM.
15 WT-TBL-CLAVE1 PIC X.
15 WT-TBL-CLAVE2 PIC X(3).
15 WT-TBL-CAMPO PIC X(10).
15 WT-TBL-INDICADOR PIC X.
* Formato del registro a ordenar
01 WR-ELEMENTO-SORT.
05 WR-SORT-CLAVE1 PIC X.
05 WR-SORT-CLAVE2 PIC X(3).
05 WR-SORT-CAMPO PIC X(10).
05 WR-SORT-INDICADOR PIC X.
*
PROCEDURE DIVISION.
*
PERFORM 1000-INICIO
PERFORM 2000-PROCESO
PERFORM 9000-FINAL
.
*
1000-INICIO.
*
INITIALIZE VARIABLES
.
*
2000-PROCESO.
* Proceso de SORT
* Indicamos las claves por las que ordenaremos ON ASCENDING ó
* ON DESCENDING
SORT TABLA-SORT
ON ASCENDING KEY SORT-CLAVE1
ON DESCENDING KEY SORT-CLAVE2
INPUT PROCEDURE 2100-PROCESO-ENTRADA
OUTPUT PROCEDURE 2200-PROCESO-SALIDA
* En la INPUT PROCEDURE cargamos los datos a ordenar
* En la OUTPUT PROCEDURE guardamos la información ordenada
* en variables del programa
* Controlamos el retorno del SORT con SORT-RETURN
IF SORT-RETURN NOT = ZEROS
DISPLAY 'ERROR EN EL SORT:' SORT-RETURN
END-IF
.
*
2100-PROCESO-ENTRADA.
* Cargamos los datos a ordenar(los de la tabla interna) en el
* fichero temporal donde se realizará la ordenación
* (ELEMENTO-SORT) con la sentencia RELEASE.
PERFORM VARYING WI-ELEM
FROM 1 BY 1
UNTIL WT-TBL-CLAVE1(WI-ELEM) = LOW-VALUES
OR WI-ELEM = 16
*
MOVE WT-TBL-CLAVE1(WI-ELEM) TO WR-SORT-CLAVE1
MOVE WT-TBL-CLAVE2(WI-ELEM) TO WR-SORT-CLAVE2
MOVE WT-TBL-CAMPO(WI-ELEM) TO WR-SORT-CAMPO
MOVE WT-TBL-INDICADOR(WI-ELEM) TO WR-SORT-INDICADOR
*
RELEASE ELEMENTO-SORT FROM WR-ELEMENTO-SORT
DISPLAY 'ELEMENTO-SORT:'WR-ELEMENTO-SORT
END-PERFORM
.
*
2200-PROCESO-SALIDA.
* Recuperamos los datos ordenados del fichero temporal con la
* sentencia RETURN y los displayamos
SET NO-FIN-TABLA-SORT TO TRUE
*
PERFORM UNTIL SI-FIN-TABLA-SORT
RETURN TABLA-SORT INTO WR-ELEMENTO-SORT
AT END
SET SI-FIN-TABLA-SORT TO TRUE
NOT AT END
MOVE WR-SORT-CLAVE1 TO WA-SORT-CLAVE1
MOVE WR-SORT-CLAVE2 TO WA-SORT-CLAVE2
MOVE WR-SORT-CAMPO TO WA-SORT-CAMPO
MOVE WR-SORT-INDICADOR TO WA-SORT-INDICADOR
*
DISPLAY 'REGISTRO->' WA-REGISTRO
*
END-RETURN
END-PERFORM
.
*
9000-FINAL.
*
STOP RUN
.
*
RESULTADO:
REGISTRO->F457CAMPO61224N
REGISTRO->F217CAMPO03312N
REGISTRO->F216CAMPO02802S
REGISTRO->L547CAMPO73985N
REGISTRO->L354CAMPO89173N
REGISTRO->M144CAMPO17114N
REGISTRO->O372CAMPO52113N
REGISTRO->Q651CAMPO24536S
REGISTRO->T487CAMPO44914S
REGISTRO->W516CAMPO92815N
¿Utilidad? Depende. Lo cierto es que pudiendo hacerlo por JCL, no tiene caso hacerlo en un programa. Pero quién sabe! Tal vez alguno de los lectores puedan darnos una idea de su uso práctico : D
SORT:
La sentencia SORT en cobol sirve para ordenar registros por un campo clave que le indiquemos. Podremos elegir varias claves y definir si el orden será ascendente o descendente.
Para el ejemplo, hemos creado un fichero temporal en nuestro programa que utilizaremos para generar en él la información ordenada. Como registros a ordenar, utilizaremos una tabla interna, de tal forma que no necesitaremos utilizar ficheros en ningún momento.
La información ordenada se cargará desde el fichero temporal al registro de salida, que podría utilizarse a lo largo de la ejecución.
Nosotros nos pararemos cuando tengamos nuestra información ordenada, y la "displayaremos" mostrándola por SYSOUT.
IDENTIFICATION DIVISION.
PROGRAM-ID. PRGSORT.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
* Fichero temporal donde guardaremos la información ordenada
SELECT TABLA-SORT ASSIGN TO DISK "SORTWORK".
*
DATA DIVISION.
FILE SECTION.
* Definición del fichero temporal
SD TABLA-SORT
DATA RECORD IS ELEMENTO-SORT.
01 ELEMENTO-SORT.
05 SORT-CLAVE1 PIC X.
05 SORT-CLAVE2 PIC X(3).
05 SORT-CAMPO PIC X(10).
05 SORT-INDICADOR PIC X.
*
WORKING-STORAGE SECTION.
* Formato del registro de salida
01 VARIABLES.
05 WA-REGISTRO.
10 WA-SORT-CLAVE1 PIC X.
10 WA-SORT-CLAVE2 PIC X(3).
10 WA-SORT-CAMPO PIC X(10).
10 WA-SORT-INDICADOR PIC X.
* Switches que utilizaremos en los bucles
01 SWITCHES.
05 SW-FIN-TABLA-SORT PIC X(1).
88 SI-FIN-TABLA-SORT VALUE 'S'.
88 NO-FIN-TABLA-SORT VALUE 'N'.
* Tabla interna con los datos a ordenar
01 TABLA.
05 WT-TBL-LISTA.
10 PIC X(15) VALUE 'F216CAMPO02802S'.
10 PIC X(15) VALUE 'M144CAMPO17114N'.
10 PIC X(15) VALUE 'Q651CAMPO24536S'.
10 PIC X(15) VALUE 'F217CAMPO03312N'.
10 PIC X(15) VALUE 'T487CAMPO44914S'.
10 PIC X(15) VALUE 'O372CAMPO52113N'.
10 PIC X(15) VALUE 'F457CAMPO61224N'.
10 PIC X(15) VALUE 'L547CAMPO73985N'.
10 PIC X(15) VALUE 'L354CAMPO89173N'.
10 PIC X(15) VALUE 'W516CAMPO92815N'.
05 REDEFINES WT-TBL-LISTA.
10 WT-TBL-ELEMENTO OCCURS 15
INDEXED BY WI-ELEM.
15 WT-TBL-CLAVE1 PIC X.
15 WT-TBL-CLAVE2 PIC X(3).
15 WT-TBL-CAMPO PIC X(10).
15 WT-TBL-INDICADOR PIC X.
* Formato del registro a ordenar
01 WR-ELEMENTO-SORT.
05 WR-SORT-CLAVE1 PIC X.
05 WR-SORT-CLAVE2 PIC X(3).
05 WR-SORT-CAMPO PIC X(10).
05 WR-SORT-INDICADOR PIC X.
*
PROCEDURE DIVISION.
*
PERFORM 1000-INICIO
PERFORM 2000-PROCESO
PERFORM 9000-FINAL
.
*
1000-INICIO.
*
INITIALIZE VARIABLES
.
*
2000-PROCESO.
* Proceso de SORT
* Indicamos las claves por las que ordenaremos ON ASCENDING ó
* ON DESCENDING
SORT TABLA-SORT
ON ASCENDING KEY SORT-CLAVE1
ON DESCENDING KEY SORT-CLAVE2
INPUT PROCEDURE 2100-PROCESO-ENTRADA
OUTPUT PROCEDURE 2200-PROCESO-SALIDA
* En la INPUT PROCEDURE cargamos los datos a ordenar
* En la OUTPUT PROCEDURE guardamos la información ordenada
* en variables del programa
* Controlamos el retorno del SORT con SORT-RETURN
IF SORT-RETURN NOT = ZEROS
DISPLAY 'ERROR EN EL SORT:' SORT-RETURN
END-IF
.
*
2100-PROCESO-ENTRADA.
* Cargamos los datos a ordenar(los de la tabla interna) en el
* fichero temporal donde se realizará la ordenación
* (ELEMENTO-SORT) con la sentencia RELEASE.
PERFORM VARYING WI-ELEM
FROM 1 BY 1
UNTIL WT-TBL-CLAVE1(WI-ELEM) = LOW-VALUES
OR WI-ELEM = 16
*
MOVE WT-TBL-CLAVE1(WI-ELEM) TO WR-SORT-CLAVE1
MOVE WT-TBL-CLAVE2(WI-ELEM) TO WR-SORT-CLAVE2
MOVE WT-TBL-CAMPO(WI-ELEM) TO WR-SORT-CAMPO
MOVE WT-TBL-INDICADOR(WI-ELEM) TO WR-SORT-INDICADOR
*
RELEASE ELEMENTO-SORT FROM WR-ELEMENTO-SORT
DISPLAY 'ELEMENTO-SORT:'WR-ELEMENTO-SORT
END-PERFORM
.
*
2200-PROCESO-SALIDA.
* Recuperamos los datos ordenados del fichero temporal con la
* sentencia RETURN y los displayamos
SET NO-FIN-TABLA-SORT TO TRUE
*
PERFORM UNTIL SI-FIN-TABLA-SORT
RETURN TABLA-SORT INTO WR-ELEMENTO-SORT
AT END
SET SI-FIN-TABLA-SORT TO TRUE
NOT AT END
MOVE WR-SORT-CLAVE1 TO WA-SORT-CLAVE1
MOVE WR-SORT-CLAVE2 TO WA-SORT-CLAVE2
MOVE WR-SORT-CAMPO TO WA-SORT-CAMPO
MOVE WR-SORT-INDICADOR TO WA-SORT-INDICADOR
*
DISPLAY 'REGISTRO->' WA-REGISTRO
*
END-RETURN
END-PERFORM
.
*
9000-FINAL.
*
STOP RUN
.
*
RESULTADO:
REGISTRO->F457CAMPO61224N
REGISTRO->F217CAMPO03312N
REGISTRO->F216CAMPO02802S
REGISTRO->L547CAMPO73985N
REGISTRO->L354CAMPO89173N
REGISTRO->M144CAMPO17114N
REGISTRO->O372CAMPO52113N
REGISTRO->Q651CAMPO24536S
REGISTRO->T487CAMPO44914S
REGISTRO->W516CAMPO92815N
lunes, 7 de febrero de 2011
Sentencia MERGE en un programa COBOL
Hemos visto en otros artículos como hacer un MERGE en un JCL. En este artículo veremos como hacerlo en un programa cobol.
¿Utilidad? Depende. Lo cierto es que pudiendo hacerlo por JCL, no veo la razón de hacerlo en un programa. Pero quién sabe! Tal vez alguno de los lectores pueda darnos una idea de su uso práctico : D
MERGE:
La sentencia MERGE en cobol sirve para unir dos ficheros teniendo en cuenta la clave por la que están ordenados. Es decir, no podemos hacer un MERGE de ficheros desordenados.
Lo que hará será "colocar" las claves que coincidan, juntas en el fichero de salida.
Para el ejemplo, utilizaremos:
2 ficheros de entrada con los datos a unir.
1 fichero temporal donde se realizará el MERGE.
Los datos de los ficheros de entrada para nuestro ejemplo serán:
FICHERO1:
A
B
C
FICHERO2:
B
C
E
Programa:
IDENTIFICATION DIVISION.
PROGRAM-ID.PRGMERGE.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
*Definición de ficheros
SELECT TABLA-MERGE ASSIGN TO DISK 'SORTWORK'.
SELECT TABLA-FICH1 ASSIGN TO FICHERO1.
SELECT TABLA-FICH2 ASSIGN TO FICHERO2.
*
DATA DIVISION.
FILE SECTION.
*Ficheros físicos
FD TABLA-FICH1
DATA RECORD IS FICHERO1.
01 FICHERO1.
05 FILLER PICTURE X.
FD TABLA-FICH2
DATA RECORD IS FICHERO2.
01 FICHERO2.
05 FILLER PICTURE X.
* Ficheros temporales
SD TABLA-MERGE
DATA RECORD IS ELEMENTO-MERGE.
01 ELEMENTO-MERGE.
05 MERGE-CLAVE1 PIC X.
*
WORKING-STORAGE SECTION.
* Variable donde guardaremos el resultado del MERGE
01 VARIABLES.
05 WA-REGISTRO.
10 WA-AUX-CLAVE1 PIC X.
* Switches para el bucle
01 SWITCHES.
05 SW-FIN-TABLA-MERGE PIC X(1).
88 SI-FIN-TABLA-MERGE VALUE 'S'.
88 NO-FIN-TABLA-MERGE VALUE 'N'.
* Registro para los datos después del MERGE
01 WR-ELEMENTO-MERGE.
05 WR-MERGE-CLAVE1 PIC X.
*
PROCEDURE DIVISION.
*
PERFORM 1000-INICIO
PERFORM 2000-PROCESO
PERFORM 9000-FINAL
.
*
1000-INICIO.
*
INITIALIZE VARIABLES
.
*
2000-PROCESO.
* Sentencia MERGE
* Juntamos FICHERO1 y FICHERO2 en TABLA-MERGE por clave
* MERGE-CLAVE1
MERGE TABLA-MERGE ASCENDING KEY MERGE-CLAVE1
USING FICHERO1 FICHERO2
OUTPUT PROCEDURE 2100-PROCESO-SALIDA
* En la OUTPUT PROCEDURE usaremos la información ya unida
IF SORT-RETURN NOT = ZEROS
DISPLAY 'ERROR EN EL MERGE:' SORT-RETURN
END-IF
.
*
2100-PROCESO-SALIDA.
* Movemos del fichero temporal al registro de salida con la
* sentencia RETURN
* Displayamos la información desde una variable definida
* en el programa
SET NO-FIN-TABLA-UNION TO TRUE
*
PERFORM UNTIL SI-FIN-TABLA-UNION
RETURN TABLA-MERGE INTO WR-ELEMENTO-MERGE
AT END
SET SI-FIN-TABLA-MERGE TO TRUE
NOT AT END
MOVE WR-MERGE-CLAVE1 TO WA-AUX-CLAVE1
DISPLAY 'REGISTRO->' WA-REGISTRO
END-RETURN
END-PERFORM
.
*
9000-FINAL.
*
STOP RUN
.
*
RESULTADO:
REGISTRO->A
REGISTRO->B
REGISTRO->B
REGISTRO->C
REGISTRO->C
REGISTRO->E
Nota: aunque no veais nigún párrafo de "abrir fichero", "leer fichero", etc., no significa que se nos haya ido la olla, es que no es necesario!
¿Utilidad? Depende. Lo cierto es que pudiendo hacerlo por JCL, no veo la razón de hacerlo en un programa. Pero quién sabe! Tal vez alguno de los lectores pueda darnos una idea de su uso práctico : D
MERGE:
La sentencia MERGE en cobol sirve para unir dos ficheros teniendo en cuenta la clave por la que están ordenados. Es decir, no podemos hacer un MERGE de ficheros desordenados.
Lo que hará será "colocar" las claves que coincidan, juntas en el fichero de salida.
Para el ejemplo, utilizaremos:
2 ficheros de entrada con los datos a unir.
1 fichero temporal donde se realizará el MERGE.
Los datos de los ficheros de entrada para nuestro ejemplo serán:
FICHERO1:
A
B
C
FICHERO2:
B
C
E
Programa:
IDENTIFICATION DIVISION.
PROGRAM-ID.PRGMERGE.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
*Definición de ficheros
SELECT TABLA-MERGE ASSIGN TO DISK 'SORTWORK'.
SELECT TABLA-FICH1 ASSIGN TO FICHERO1.
SELECT TABLA-FICH2 ASSIGN TO FICHERO2.
*
DATA DIVISION.
FILE SECTION.
*Ficheros físicos
FD TABLA-FICH1
DATA RECORD IS FICHERO1.
01 FICHERO1.
05 FILLER PICTURE X.
FD TABLA-FICH2
DATA RECORD IS FICHERO2.
01 FICHERO2.
05 FILLER PICTURE X.
* Ficheros temporales
SD TABLA-MERGE
DATA RECORD IS ELEMENTO-MERGE.
01 ELEMENTO-MERGE.
05 MERGE-CLAVE1 PIC X.
*
WORKING-STORAGE SECTION.
* Variable donde guardaremos el resultado del MERGE
01 VARIABLES.
05 WA-REGISTRO.
10 WA-AUX-CLAVE1 PIC X.
* Switches para el bucle
01 SWITCHES.
05 SW-FIN-TABLA-MERGE PIC X(1).
88 SI-FIN-TABLA-MERGE VALUE 'S'.
88 NO-FIN-TABLA-MERGE VALUE 'N'.
* Registro para los datos después del MERGE
01 WR-ELEMENTO-MERGE.
05 WR-MERGE-CLAVE1 PIC X.
*
PROCEDURE DIVISION.
*
PERFORM 1000-INICIO
PERFORM 2000-PROCESO
PERFORM 9000-FINAL
.
*
1000-INICIO.
*
INITIALIZE VARIABLES
.
*
2000-PROCESO.
* Sentencia MERGE
* Juntamos FICHERO1 y FICHERO2 en TABLA-MERGE por clave
* MERGE-CLAVE1
MERGE TABLA-MERGE ASCENDING KEY MERGE-CLAVE1
USING FICHERO1 FICHERO2
OUTPUT PROCEDURE 2100-PROCESO-SALIDA
* En la OUTPUT PROCEDURE usaremos la información ya unida
IF SORT-RETURN NOT = ZEROS
DISPLAY 'ERROR EN EL MERGE:' SORT-RETURN
END-IF
.
*
2100-PROCESO-SALIDA.
* Movemos del fichero temporal al registro de salida con la
* sentencia RETURN
* Displayamos la información desde una variable definida
* en el programa
SET NO-FIN-TABLA-UNION TO TRUE
*
PERFORM UNTIL SI-FIN-TABLA-UNION
RETURN TABLA-MERGE INTO WR-ELEMENTO-MERGE
AT END
SET SI-FIN-TABLA-MERGE TO TRUE
NOT AT END
MOVE WR-MERGE-CLAVE1 TO WA-AUX-CLAVE1
DISPLAY 'REGISTRO->' WA-REGISTRO
END-RETURN
END-PERFORM
.
*
9000-FINAL.
*
STOP RUN
.
*
RESULTADO:
REGISTRO->A
REGISTRO->B
REGISTRO->B
REGISTRO->C
REGISTRO->C
REGISTRO->E
Nota: aunque no veais nigún párrafo de "abrir fichero", "leer fichero", etc., no significa que se nos haya ido la olla, es que no es necesario!
Suscribirse a:
Entradas (Atom)