viernes, 29 de abril de 2011

¿Reforma tecnológica en el sector financiero?

Raúl Gómez Martínez, Gerente de Cuentas Sector Banca de MTP, realiza en FinancialTech una reflexión sobre la oportunidad de reforma tecnológica en el sector financiero como consecuencia de la crisis.

Argumenta, con buen criterio, que detrás de cada fusión/adquisición entre entidades financieras se localiza como uno de los objetivos principales reducir los costes de servicios centrales y plataformas tecnológicas. Lo que en la teoría resulta evidente, en la práctica puede llegar a ser muy complejo, y derivar grandes costes que deberán ser amortizados a largo plazo.

Además de criticar la obsolescencia de las plataformas tecnológicas que soportan los sistemas financieros ("las mismas" que hace 50 años), también critica el nivel de madurez del ciclo de vida del software. Como referencia cita a Caixa Galicia la primera entidad financiera europea y segunda en el mundo en obtener el nivel 5 de CMMI.

Desconozco si habla desde el conocimiento personal de la arquitectura de Caixa Galicia, pero si no es el caso le podría pasar el contacto de algún "colega" de profesión con el que puede discutir lo sencillo que son los mantenimientos y lo rápido que son los desarrollos de software en Caixa Galicia gracias al CMMI 5. :)

Opinión en FinancialTech

jueves, 28 de abril de 2011

CONSULTIRAS 7 : "Loco del Cobol Vol. 2"

Hay gente que está loca, y después... bueno, después simplemente vengo yo...

(Pinchad en la imagen para hacerla más grande

miércoles, 27 de abril de 2011

Usando CICS: transacción CEMT.

A todos aquellos que alguna vez hemos trabajado con CICS nos sonará la transacción CEMT. Es una transacción propia del sistema que nos permite manejar funciones del "terminal maestro".

Para ejecutar esta transacción, podemos ir paso a paso navegando por las opciones, o teclear directamente una solicitud completa.

1.Al teclear CEMT y pulsar intro:
STATUS: ENTER ONE OF THE FOLLOWING

Discard
Inquire
Perform
Set


2.Solicitud completa:
CEMT INQUIRE TASK

o en abreviado como suele ser más común...
CEMT I TA

Sí, esa "I" famosa viene de "Inquire" (preguntar).

Como veis las opciones principales de la transacción son 4: Discard, Inquire, Perform y Set. Nosotros vamos a centrarnos en la opción "Inquire" por ser la que más solemos necesitar cuando estamos probando un programa CICS. Si queréis consultar las opciones de Discard, Perform y Set está todo en la web de IBM donde habla de CEMT-Master Terminal.

Comandos CEMT Inquire

La opción Inquire tiene a su vez muchas opciones, como TASK, TRANS, PROG, etc. que nos sonarán. Para empezar vamos a ver la lista completa de opciones posibles:


INQ

STATUS: ENTER ONE OF THE FOLLOWING OR HIT ENTER FOR DEFAULT

AUTInstmodel DUmpds       MODename       TDqueue
AUTOinstall  ENQ          MONitor        TErminal
AUXtrace     ENQModel     Netname        TRAnsaction
Bean         EXci         PArtner        TRDumpcode
BRfacility   FEConnection PROCesstype    TSModel
CFDTpool     FENode       PROFile        TSPool
CONnection   FEPOol       PROGram        TSQueue
CORbaserver  FEPRopset    REquestmodel   UOW
DB2Conn      FETarget     RRms           UOWDsnfail
DB2Entry     FIle         STAtistics     UOWLink
DB2Tran      Gtftrace     STReamname     Vtam
DEletshipped INttrace     SYDumpcode     Web
Dispatcher   IRc          SYStem
DJar         JModel       TAsk
DOctemplate  JOurnalname  TCLass
DSAs         JVmpool      TCPIP
DSName       Line         TCPIPService


Como veis son unas cuantas! Vamos a ver en detalle algunas de ellas.

FIle

Es habitual en las diferentes instalaciones que existan ficheros accesibles para CICS para controlar temas como la oficina asociada a un terminal, etc. Para acceder a este tipo de ficheros (VSAM, BDAM, base de datos...) lo primero que hacemos es abrirlos desde CICS:

CEMT I FI (abreviatura máxima)
Lista

Detalle


Para abrir un fichero situamos el cursor encima del estado (Openstatus) "Clo" y lo cambiamos por "Ope". Al pulsar intro se guardarán los cambios.
Ahora ya podremos entrar a editar el fichero desde nuestra sesión de TSO.

Otras opciones modificables son:
Addstatus    (Addable/Noaddable)
Browsestatus (Browse/Nobrowse)
Deletestatus (Delete/Nodelete)
Disposition  (Old/Share)
Emptystatus  (Emptyreq/Noemptyreq) Solo para VSAM
Enablestatus (Enabled/Unenabled/Disabled)
Readstatus   (Read/Noread)
Rlsaccess    (Rls/Notrls) Solo para VSAM
Table        (Nottable/Cftable/Cicstable/Usertable)
Updatestatus (Update/Noupdate)


Todos los detalles en la web de IBM sección CEMT INQUIRE FILE : )

PROGram

Esta opción nos muestra la lista de programas, mapas, etc. definidos en nuestro sistema. Si no le indicamos nada nos cargará la lista de TODOS los programas. Si queremos "filtrar" podemos indicar entre paréntesis el nombre del programa, o las primeras letras.

CEMT I PROG(XX*) (abreviatura máxima)
Lista

Detalle


Las opciones modificables son:
Executionset (Dplsubset/Fullapi)
Sharestatus  (Shared/Private)
Status       (Enabled/Disabled)


Todos los detalles en la web de IBM sección CEMT INQUIRE PROGRAM : )

SYStem

Esta opción nos devuelve información sobre el sistema CICS. En ella podemos consultar información como la conexión DB2 que está utilizando (Db2conn), el máximo de tareas simultáneas que puede ejecutar (Maxtasks), tiempo máximo antes de que el sistema asuma que una tarea está embuclada (Runaway), etc.

CEMT I SYS (abreviatura máxima)
Lista


Las opciones modificables son:
Aging        (número entre 0 y 65535)
Akp          (número entre 200 y 65535)
Dsalimit
Dtrprogram
Edsalimit
Logdefer     (número entre 0 y 65535)
Maxtasks     (número entre 0 y 999)
Mrobatch     (número entre 1 y 255)
Progautoctlg (Ctlgall/Ctlgmodify/Ctlgnone)
Progautoexit
Progautoinst (Autoactive/Autoinactive)
Runaway      (número entre 500 y 2700000 ó 0)
Scandelay    (número entre 0 y 5000)
Time         (número ente 100 y 3600000 y mayor que el valor de SCANDELAY)


Todos los detalles en la web de IBM sección CEMT INQUIRE SYSTEM : )

TAsk

En ocasiones necesitaremos poder purgar una tarea que se está ejecutando (por ejemplo cuando se nos ha embuclado y estamos llenando la cola del CICS de displays,
y alguien está a punto de matarnos...).

CEMT I TA (abreviatura máxima)
Lista

Detalle


Para "terminar" una tarea, basta con poner una "P" al lado de la linea de la tarea que queremos purgar.
En la opción Tra (Tranid) vendrá el nombre de nuestra transacción y en la opción Use (Userid) nuestro usuario (no vayamos a tirar la transacción del vecino).

Las opciones modificables son:
Priority (número de 0 a 255 siendo 255 la prioridad más alta)


Todos los detalles en la web de IBM sección CEMT INQUIRE TASK : )

TRAnsaction

Esta opción es muy útil para ver la transacción asociada a un programa y viceversa.
Nos devuelve información sobre las transacciones del sistema.

CEMT I TRANS (abreviatura máxima)
Lista


Podemos añadir a la consulta la opción PROG. Por ejemplo:

CEMT I TRANS(*) PROG(PROGRAMA)
Nos devolvería la transacción asociada al programa "PROGRAMA".

CEMT I TRANS(PV40) PROG(*)
Nos devolvería el programa asociado a la transacción PV40.

Las opciones modificables son:
Priority     (número de 0 a 255 siendo 255 la prioridad más alta)
Purgeability (Purgeable/Notpurgeable)
Status       (Enabled/Disabled)
Tclass


Todos los detalles en la web de IBM sección CEMT INQUIRE TRANSACTION : )

Y hasta aquí la segunda incursión en el mundo del CICS^^
Si queréis que entremos en detalle de alguna otra opción/transacción dejad un comentario.

lunes, 25 de abril de 2011

Lo mejor de la Semana Santa: lunes 18 a domingo 24.

La Semana Santa ha terminado, y toca volver al curro. Y a nosotros, como cada lunes, nos toca hacer recuento de lo que se ha leído en la última semana. Hay que decir que no ha sido mucho, pero es que estábamos de vacaciones^^

  1. Sort vol.2: OUTREC.
  2. JCL básico: IDCAMS, IEFBR14, IEBGENER.
  3. Comandos TSO vol.1: Comandos del editor.
  4. JCL Básico III: Sentencia EXEC.
  5. ICETOOL(I): SPLICE; cruce de ficheros.
  6. CURSOR ii: ROWSET.
  7. LOAD y UNLOAD: carga y descarga.
  8. WORKING-STORAGE: definiendo variables.
  9. OFFSET y S0C7, ¿Cómo localizar el error?
  10. Estudio del mercado laboral español

Esta semana retomamos la saga de "JCL básico" y continuaremos avanzando con el amigo CICS. Si veis que hay alguna otra cosa que os urge más nos lo decís.
Ánimo que esta semana vuelve a ser de 5 días!

JCL Básico IV: Sentencia DD (Parte II)

Continuamos con la segunda parte de este artículo. Vamos a hablar ahora de los diferentes parámetros que puede tener la sentencia DD. Los parámetros pueden ser de dos tipos, posicionales o de palabras clave. Vamos a ver ambos por separado:

PARÁMETROS POSICIONALES:
Asterisco *
El asterisco evita tener que definir un fichero, únicamente indicaremos los datos. La finalización de datos se indica con ( /* ) o con ( // ). Por ejemplo:

//PAS01 EXEC PGM=MIPROGRAMA
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA2 DD *
AQUI_ESCRIBIMOS_LOS_DATOS_DE_ENTRADA2
//SALIDA1  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


Otra utilidad es en los SORT:
//SYSIN DD *
SORT FIELDS=(1,4,CH,A)
/*


DATA
Similar al asterisco con la diferencia de que la finalización de datos se indica con el delimitador /*.

NOTA: Aunque poco usado, este delimitador puede ser modificado para no llevarnos a confusión.
Indicando DLM='##', sustituimos el delimitador /* por el ##. Sirve también para el parámetro asterisco *
Ejemplo de uso:

//PAS01 EXEC PGM=MIPROGRAMA
//SYSIN DD DATA,DLM=‘##’
SORT FIELDS=(1,1,CH,A)

##--> Delimitador modificado


DUMMY
Indica un fichero ficticio. El jcl tratará este fichero como si fuera real pero no
leerá o escribirá ningun dato sobre él. Muy útil cuando se quiere ejecutar un job sin generar algún fichero que no nos interese.

Aclaraciones: El programa utilizado ha de realizar el open y el close como si de un fichero real se tratara. En el siguiente ejemplo se ejecuta el programa MIPROGRAMA del mismo modo que lo haría normalmente, pero en el fichero de SALIDA1 no se obtendrán datos, sin embargo el funcionamiento del programa será exactamente el mismo.

//PAS01 EXEC PGM=MIPROGRAMA
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DUMMY
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


DYNAM
Sirve para asignar memoria dinámica a nuestro paso. Pondremos tantas DD DYNAM como
ficheros tengamos. Si no la indicamos el jcl se sirve de la memoria dinámica indicada en la sentencia EXEC con el DYNAMNBR. Pero también se pueden combinar ambas utilidades.
Veamos 3 posibles ejemplos prácticos(los 3 asignan la misma memoria, dejo a vuestra elección el que más os guste):

//PAS01 EXEC PGM=MIPROGRAMA
//DD1 DD DYNAM
//DD2 DD DYNAM
//DD3 DD DYNAM
//DD4 DD DYNAM

//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DUMMY
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//DD1 DD DYNAM
//DD2 DD DYNAM
//DD3 DD DYNAM
//DD4 DD DYNAM

//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DUMMY
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DUMMY
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


PARÁMETROS PALABRAS CLAVE
Pueden codificarse en cualquier orden y son opcionales.

DDNAME
Funciona de forma similar a un procedimiento o copy. Tú defines una variable(por
ejemplo TEXTO) y almacenas en ella los datos que quieras. Después únicamente has de hacer una llamada (DDNAME=ENTR1) para utilizar ese texto. Se ve muy claro con un ejemplo:

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DDNAME=FICHERO2
//SALIDA1  DD DSN=xxxx.nombre.fichero2,
//            DISP=(NEW,CATLG,DELETE),...
...
...
//PAS01 EXEC FERPROC
//PASO01.FICHERO2 DD *
AQUI_ESCRIBIMOS_LOS_DATOS_DE_NUESTRO_FICHERO
/*



SYSOUT
Con ella indicas al jcl a qué cola enviar la salida.
Con SYSOUT=* la ejecución del jcl va a la cola que tengas indicada en el MSGCLASS de la cabecera.
Con SYSOUT=2 la ejecución del jcl va a la cola que el host considere que es la cola 2 (según la arquitectura donde nos encontremos variará).


COPIES
Indica el número de copias que queremos del fichero donde se indica. Hay un máximo de 255 copias.

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//SYSPRINT DD SYSOUT=2,COPIES=2
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DSN=xxxx.nombre.fichero2
//            DISP=(NEW,CATLG,DELETE),...
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


DEST
Sirve para indicar el destino del SYSOUT. Por ejemplo, con DEST=LOCAL la ejecución va al terminal por defecto de la instalación:

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//SYSPRINT DD SYSOUT=2,DEST=LOCAL
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DSN=xxxx.nombre.fichero2
//            DISP=(NEW,CATLG,DELETE),...
//SALIDA2  DD DSN=xxxx.nombre.fichero3,
//            DISP=(NEW,CATLG,DELETE),...


FREE
Este comando libera un fichero cuando el jcl no lo use y, de ese modo, que otro jcl lo pueda usar. Para los amantes del rendimiento, muy útil para evitar esperas innecesarias. Puede tener dos valores:
FREE=END --> el fichero se libera al terminar el paso donde se esté ejecutando
FREE=CLOSE --> el fichero se libera en cuanto el programa lo cierra


HOLD
Retiene la ejecución de la salida del jcl hasta que el operador de la consola lo
libera. Solo se usa en el SYSOUT. Si no se indica, por defecto está desactivado(HOLD=NO). Para activarlo: HOLD=YES.

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//SYSPRINT DD SYSOUT=2,HOLD=YES
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DSN=xxxx.nombre.fichero2
//            DISP=(NEW,CATLG,DELETE),...


UCS
Solo dejo reseñado lo que he leído sobre este comando, no sé muy bien como funciona pues nunca lo probé, pero si a alguien le sirve ahí va:
Sirve para indicar el juego de caracteres que utilizará la cola de impresión. Los posibles valores son:
UCS=indicar_Juego_de_Caracteres,FOLD,VERIFY

En juego de caracteres se indican los caracteres
FOLD - es opcional, permite modificar el juego de caracteres por otro(por ejemplo cambiar mayúsculas a minúsculas)
VERIFY - el operador verificará el juego de caracteres

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//SYSPRINT DD SYSOUT=2,UCS=(YN,,VERIFY)
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DSN=xxxx.nombre.fichero2
//            DISP=(NEW,CATLG,DELETE),...


OUTLIM
Sirve para indicar el número máximo de registros que saldrán en los ficheros de tipo SYSOUT. Muy útil para cuando tenemos muchos displays y se nos desborda la ejecución.

Por ejemplo con OUTLIM=1000 cuando la ejecución llegue a 1000 registros se para el job.

//PAS01 EXEC PGM=MIPROGRAMA,DYNAMNBR=4
//SYSPRINT DD SYSOUT=2,OUTLIM=1000
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//ENTRADA1 DD DSN=xxxx.nombre.fichero1,DISP=SHR
//SALIDA1  DD DSN=xxxx.nombre.fichero2
//            DISP=(NEW,CATLG,DELETE),...


El valor máximo es 16777215. Si no se indica se considera ilimitado.

Hemos explicado los posibles parámetros en la ficha DD. En el próximo artículo explicaré algo mucho más interesante, los posibles parámetros para los ficheros de salida de nuestros pasos: cilindros, space, ficheros en cinta, longitudes de ficheros, etc...

viernes, 22 de abril de 2011

CONSULTIRAS 6: "Host colgado"

Muchas veces, el HOST parece no responder, que ha adquirido vida propia y te ha dejado forever alone, pero en el Consultorio tenemos la respuesta para todo (o casi todo...).


(Pincha en la imagen para hacerla más grande)

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

lunes, 18 de abril de 2011

Lo mejor de la semana: lunes 11 a domingo 17.

Un lunes más, hacemos recuento de visitas. Esto es lo que más han consultado los lectores:

  1. Sort vol.2: OUTREC.
  2. JCL básico: IDCAMS, IEFBR14, IEBGENER.
  3. Programas con DB2 I: SELECT, INSERT, UPDATE y DELETE.
  4. Sort vol.1: SORT, INCLUDE.
  5. ICETOOL(I): SPLICE; cruce de ficheros.
  6. WORKING-STORAGE: definiendo variables.
  7. LOAD y UNLOAD: carga y descarga.
  8. Programas con DB2 III: COUNT, MAX y FOR UPDATE.
  9. Ejemplo 3: leer de fichero y escribir en fichero.
  10. JCL Básico I: ¿Qué es JCL?

Está bien, me rindo...

Hoy hemos hecho la presentación del amigo CICS, que pronto será un habitual del Consultorio. Veremos todo lo que tiene que contarnos en las próximas semanas.

Ánimos a todos, que esta semana sólo tiene 3 días! (en España al menos^^)

CICS, ese desconocido transaccional

CICS es el sistema de proceso de transacciones que encontraremos en la mayor parte de instalaciones mainframe.

CICS = Customer Information Control System = Sistema de Clientes para Control de Información

El CICS se ejecuta bajo el control del sistema operativo junto con el resto de aplicaciones de la instalación, incluidos los procesos por lotes (batch).

Es interesante mencionar en este punto, la diferencia entre procesos BATCH y ONLINE.

Los procesos batch son conjuntos de programas que tienen como entrada ficheros o consultas sobre la base de datos, generalmente voluminosos, y procesan los datos generando como salida listados para consultar el resultado de los procesos que son distribuidos posteriormente a cada departamento/oficina responsable de los mismos. Un ejemplo sería la liquidación de préstamos, en la cual se tratarían todos los préstamos de la entidad susceptibles de ser liquidados, lo cual, dependiendo del tamaño de la entidad puede llegar a consumir un tiempo considerable.

Los procesos on-line permiten procesar programas muy cortos (procesan uno o unos pocos registros) y por tanto generan una contestación casi inmediata hacia el terminal que ha solicitado su ejecución. Un ejemplo sería el empleado de una entidad que desde el terminal del que dispone en su oficina consulta los datos de un cliente a partir de su dni. Dicha consulta es muy específica y el proceso se realizará inmediatamente (a no ser que nos quedemos embuclados claro...).

Retomando el tema principal, CICS se encarga justamente de estos procesos, los de operativa online, y su función es establecer la unión entre los terminales "tontos" del usuario y la lógica de negocio.

Cada una de las peticiones que se recibe desde un terminal, constituye una transacción, la cual crea una unidad de trabajo o tarea para la CPU. Una transacción es cada una de las peticiones que realiza un usuario al host, el cual ejecuta un programa para realizar el procesado de los datos y devuelve los resultados al terminal.

Para muchos desarrolladores host, la gestión del CICS es completamente transparente y se limita a conocer que cada vez que queramos construir un programa online para ser usado desde un terminal tenemos que poner un párrafo general de la instalación xxxx para recibir los datos y un párrafo yyyy para enviarlos.

Esperemos que este primer y breve artículo sirva para hacerse una idea general de "eso" que hay entre el terminal y el host. A partir de aquí llega lo interesante...

Continuará

viernes, 15 de abril de 2011

Estudio del mercado laboral español

Desde Consultorio Cobol sentíamos curiosidad por comparar la demanda del mercado laboral español en algunas de las principales tecnologías informáticas. Aquí os dejamos los resultados que hemos obtenido:

Java

El rey de los lenguajes de programación actual orientados a objetos, desarrollado por Sun Microsystems a principios de los años 90. La suma de las ofertas encontradas en Madrid y Barcelona representa el 80% del total, siendo una tecnología demandada en todo el territorio español. El sueldo medio ofertado ronda los 27.000 euros brutos anuales y no ha sufrido variaciones en el último año.



Ofertas que solicitan Java : 1305 ofertas encontradas

Principales provincias :

# Madrid (770)
# Barcelona (282)
# Sevilla (32)
# A Coruña (32)
# Vizcaya (27)

.NET

El framework de Microsoft para el desarrollo de aplicaciones. Sigue la misma tendencia en cuanto a distribución geográfica y salarios que Java, pero siendo el número de ofertas mucho menor. Entre Madrid y Barcelona suponen el 77% del total y el sueldo medio ronda los 27.000 euros brutos anuales sin sufrir variaciones en el último año.



Ofertas que solicitan .NET : 706 ofertas encontradas

Principales provincias :

# Madrid (375)
# Barcelona (170)
# Vizcaya (24)
# Valencia/València (17)
# Asturias (16)

Sap

El mayor proveedor independiente de software de la Unión Europea demuestra su importancia en el mercado español. La oferta de Madrid y Barcelona supone un 83% del total. Es importante resaltar la diferencia del sueldo medio frente a otras tecnologías, siendo muy elevado en el caso de Sap, ya que ronda los 36.000 euros brutos anuales y en progresión ligeramente ascendente en el último año.



Ofertas que solicitan Sap : 544 ofertas encontradas

Principales provincias :

# Madrid (305)
# Barcelona (147)
# Vizcaya (15)
# Sevilla (13)
# Zaragoza (8)

Cobol

El "lenguaje de programación universal" para la informática de gestión todavía goza de buena salud, pero como los resultados arrojan quizás sea uno de los lenguajes donde la demanda se encuentra muy concentrada en Madrid (75%). El sueldo medio de un profesional Cobol ronda los 29.000 euros brutos anuales, observandose un ligero ascenso en los últimos meses.



Ofertas que solicitan Cobol : 404 ofertas encontradas

Principales provincias :

# Madrid (304)
# Barcelona (41)
# Valencia/València (8)
# Murcia (6)
# Ciudad Real (6)

Pl-SQL

Lenguaje de programación, por excelencia, incrustado en Oracle. Presenta los peores números tanto en cantidad de ofertas como en sueldo medio (26.000 euros brutos/anuales). Puede considerarse que posee una demanda dispersa, ya que Madrid y Barcelona solamente suman el 76% del total. La progresión del salario es ligeramente ascendete en el último año.



Ofertas que solicitan Pl-SQL : 274 ofertas encontradas

Principales provincias :

# Madrid (160)
# Barcelona (50)
# Valencia/València (13)
# Vizcaya (9)
# Illes Balears (7)

En cuanto a los principales gestores de bases de datos resaltamos los siguientes datos en cuanto a la cantidad de ofertas:

Oracle

Ofertas que solicitan Oracle : 1112 ofertas encontradas

Principales provincias :

# Madrid (655)
# Barcelona (241)
# Vizcaya (29)
# Valencia/València (29)
# Sevilla (26)

DB2

Ofertas que solicitan DB2 : 407 ofertas encontradas

Principales provincias :

# Madrid (303)
# Barcelona (39)
# Valencia/València (9)
# A Coruña (8)
# Asturias (8)

MySQL

Ofertas que solicitan DB2 : 429 ofertas encontradas

Principales provincias :

# Madrid (190)
# Barcelona (136)
# A Coruña (13)
# Vizcaya (12)
# Pontevedra (8)

Fuente: Infojobs

jueves, 14 de abril de 2011

CONSULTIRAS 5: "Cruce de ficheros"

Nunca un cruce de ficheros fué tan complicado...
(Pincha en la imagen para hacerla más grande)

lunes, 11 de abril de 2011

Lo mejor de la semana: lunes 04 a domingo 10.

Vuelve a ser lunes y toca hacer recuento de la semana anterior:

  1. Sort vol.2: OUTREC.
  2. ICETOOL(I): SPLICE; cruce de ficheros.
  3. WORKING-STORAGE: definiendo variables.
  4. JCL básico: IDCAMS, IEFBR14, IEBGENER.
  5. Programas con DB2 III: COUNT, MAX y FOR UPDATE.
  6. Ejemplo 3: leer de fichero y escribir en fichero.
  7. Sentencia SORT en un programa COBOL.
  8. Programas con DB2 I: SELECT, INSERT, UPDATE y DELETE.
  9. Sort vol.1: SORT, INCLUDE.
  10. JCL Básico I: ¿Qué es JCL?

Bueno, bueno, no voy a hacer comentarios sobre el número 1...

Esta semana hemos arrancado con la saga de las Consultas SQL, muy útiles en ocasiones para lanzar desde SPUFI o desde el DB2 admin. Esperamos que os sirvan de ayuda : )

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.

viernes, 8 de abril de 2011

EspacioMonzón, respuesta e innovación

EspacioMonzón, Centro de Servicios Tecnológicos en Aragón perteneciente a Informática El Corte Inglés, se encuentra a la cabeza en capacidad de respuesta e innovación en las áreas de soporte, digitalización y desarrollo web a los tres años de su apertura.

Alberto Larraz, consejero de Economía, Hacienda y Empleo del Gobierno de Aragón explica los inicios del proyecto, que supuso una inversión de cinco millones de euros: “De la crisis de hace tres años surgió la necesidad compartida con el alcalde de Monzón y la Consejería de Economía de llevar a cabo un proyecto muy grande con ansiedad de salir adelante. Encontramos en Iecisa un partner muy potente, -de hecho es de las 12 empresas más importantes para el Gobierno de Aragón-, para este proyecto y conseguimos entre todos crear este centro de trabajo, que nos ha permitido recoger personas fuera de Aragón y crear nuevas infraestructuras”.

A día de hoy EspacioMonzón tiene empleadas a 160 personas, repartidas en las áreas de help-desk en horario 24x7, digitalización de documentos, -el grueso del centro con 70 profesionales-, factoría de software especializada, sobre todo, en programación Java, Vignette y algo de Cobol, y en el centro de formación.

Enrique Muñoz, director de Relaciones Institucionales de Informática El Corte Inglés, indica que el Centro de Servicios Tecnológicos todavía tiene un importante potencial de crecimiento para los próximos años. “Tenemos una capacidad ilimitada de crecer. Aún tenemos muchos metros cuadrados para absorber más personal, pero vendrá determinado por las oportunidades de negocio que se generen”, asegura.

Desde Consultorio Cobol esperamos que estas predicciones se cumplan y se incrementen las posibilidades para los profesionales del sector.

Artículo Computing.es

jueves, 7 de abril de 2011

CONSULTIRAS 4: "Visita al cliente"

No voy a hacer ningún comentario al respecto...


(Pincha en la imagen para verla más grande)

miércoles, 6 de abril de 2011

Proceso de un programa PL/I

El proceso del programa comienza en donde nosotros queramos, aunque por poner un poco de orden, podemos decir que empazará después de que acabemos de definir todas las variables que vayamos a necesitar.

INFORMANDO VARIABLES

En PL/I la manera de informar variables es "asignándoles" un valor:
DCL CAMPO1 CHAR(3) INIT ('123');
DCL CAMPO2 CHAR(3);

CAMPO2 = CAMPO1;


Ahora CAMPO2 valdrá '123'.

Vamos a ver algunos ejemplos de asignaciones denominadas "simples", es decir, la asignación se hace entre variables del mismo tipo (numéricos con numéricos, alfanuméricos con alfanuméricos).

Ejemplo 1: Campos numéricos.
DCL CAMPO_NUM1 DEC FIXED (3,2) INIT (0);
DCL CAMPO_NUM2 DEC FIXED (6,3) INIT (0);

CAMPO_NUM1 = 1.23;
CAMPO_NUM2 = CAMPO_NUM1;


Ahora CAMPO_NUM2 valdrá 001.230.

CAMPO_NUM2 = 456.789;
CAMPO_NUM1 = CAMPO_NUM2;


Ahora CAMPO_NUM1 valdrá 6.78.
Como podéis ver, mantiene la posición del punto decimal.

En las asginaciones de campos numéricos también podremos guardar operaciones artiméticas:

CAMPO_NUM1 = CAMPO_NUM2/2 + CAMPO_NUM3 * (CAMPO_NUM4 - CAMPO_NUM5) ** 2;


Y se aplican las mismas reglas de prioridades que en matemáticas (el doble asterisco es la potencia).

Ejemplo 2: campos alfanuméricos.
DCL ALFANUM1 CHAR (5)  INIT(' ');
DCL ALFANUM2 CHAR (11) INIT (' ');

ALFANUM1 = 'COBOL';
ALFANUM2 = ALFANUM1;


Ahora ALFANUM2 valdrá 'COBOL       '.

ALFANUM2 = 'CONSULTORIO';
ALFANUM1 = ALFANUM2;


Ahora ALFANUM1 valdrá 'CONSU'.

Usando el operador de concatenación || podemos guardar varios campos en una variable:
DCL CAMPO1 CHAR(10) INIT ('COMO MOLA ');
DCL CAMPO2 CHAR(20) INIT ('EL CONSULTORIO COBOL');
DCL CAMPO3 CHAR(30);

CAMPO3 = CAMPO1||CAMPO2;


Ahora CAMPO3 contendrá 'COMO MOLA EL CONSULTORIO COBOL' :D

Ejemplo 3: matrices (tablas internas).
DCL TABLA(3) CHAR(1);


Para utilizar un elemento de una matriz tendremos que indicar el índice del elemento entre paréntesis.

TABLA(1) = 'A';
TABLA(2) = 'B';
TABLA(3) = 'C';


Ahora el elemento 1 de la tabla valdrá 'A', el elemento 2 valdrá 'B', y el elemento 3 valdrá 'C'.

Para tablas de 2 dimensiones se indicarán los dos índices entre paréntesis.
DCL TABLA_DOBLE(2,3) CHAR(1);

Y en las asignaciones también se indicarán los dos índices:
TABLA_DOBLE(1,1) = 'A';


INICIALIZANDO VARIABLES

La inicialización de variables en PL/I se hace en el momento de declararlas, con la sentencia INIT que vimos en el artículo del "Esquema de un programa pl/i".

Vamos a ver algunos ejemplos:
DCL CAMPO_ALFANUM CHAR(10)  INIT(' '); Se rellena con espacios. Para campos alfanuméricos el valor se indica entre comillas simples ''.
DCL CAMPO_ALFANUM CHAR(100) INIT((100)'-'); Se rellena con 100 guiones.
DCL CAMPO_NUM PIC 10(9)        INIT(0); Se rellena con ceros. Para campos numéricos, el valor se indica sin comillas.
DCL CAMPO_DEC DEC FIXED (10,3) INIT(0); Se rellena con ceros.

DCL TABLA1 DEC FIXED(2,2) INIT(1,2,3,4);
Asigna valores a cada elemento de la tabla:
TABLA1(1,1) = 1
TABLA1(1,2) = 2
TABLA1(2,1) = 3
TABLA1(2,2) = 4

DCL TABLA1 DEC FIXED(2,2) INIT(4(0));
Asigna ceros a los 4 elementos de la tabla.



CONDICIONES

Para expresar condiciones en PL/I se utilizará el IF/ELSE de toda la vida, pero con sus particularidades.

Ejemplo 1: IF.
IF CAMPO1 = CAMPO2
   THEN CAMPO1 = 2;


Al poner el ; finalizamos la sentencia IF (no hay que cerrarla con un END-IF como en cobol).

Ejemplo 2: IF/ELSE.
IF CAMPO1 = CAMPO2
   THEN CAMPO1 = 2;
ELSE CAMPO1 = 1;


La condición finaliza con el ; de la parte del ELSE.
Puede darse el caso de que no queramos realizar ninguna acción para la condición del IF, sino sólo en el caso contrario (ELSE):

IF CAMPO1 = CAMPO2 THEN;
ELSE CAMPO1 = 1;


Ejemplo 3: IF/ELSE con DO.
IF CAMPO1 = CAMPO2
   THEN DO;
          CAMPO1 = 2;
          CAMPO2 = 1;
        END;
ELSE DO;
       CAMPO1 = 1;
       CAMPO2 = 2;
     END;


Cuando dentro de un IF o un ELSE hay más de una expresión, todas ellas se incluirán dentro de la sentencia DO/END.

Los operadores que se utilizan en las condiciones serán:
= : igual a
¬= : distinto
& : y
| : o
< : menor que
> : mayor que
<= : menor o igual
>= : mayor o igual
¬< : no menor que
¬> : no mayor que

Otra manera de incluir una condición es con la sentencia SELECT. Viene a ser el equivalente al EVALUATE de Cobol, pero hay que tener cuidado porque no funcionan exactamente igual.

Si queremos poner como condición el valor que tome una variable:
SELECT(CAMPO_1);
  WHEN(1);
  WHEN(2)   CAMPO_2 = 2;
  OTHERWISE CAMPO_2 = 0;
END;


Si queremos validar que se cumple una condición:
SELEC;
  WHEN(CAMPO_1 = CAMPO_2);
  WHEN(CAMPO_1 < CAMPO_2) CAMPO_3 = 2;
  OTHERWISE CAMPO_3 = 0;
END;


Fijaos en el primer WHEN de los dos ejemplos. Cuando un WHEN finaliza con ; significa que para ese caso no haremos nada. Sería el equivalente a poner un CONTINUE en Cobol.
MUY IMPORTANTE no confundir con el caso del EVALUATE, donde al poner dos WHEN seguidos significa que el código que venga a continuación se realizará para los dos WHEN:

EVALUATE WX-CAMPO1
  WHEN 1
  WHEN 2
       DISPLAY 'CAMPO1 ES 1 o 2'
  WHEN OTHER
       CONTINUE
END-EVALUATE


El display se mostrará para WX-CAMPO1 = 1 y WX-CAMPO1 = 2.

En el caso del SELECT, se indicarán los dos valores en el mismo WHEN:

SELEC CAMPO_1;
  WHEN(1,2) PUT EDIT ('CAMPO_1 ES 1 o 2') (A);
  OTHERWISE;
END;


Para terminar decir que en caso de que dentro de un WHEN queramos escribir más de una instrucción, tendremos que usar el DO/END como en el caso del IF.

BUCLES

En PL/I los bucles se codifican con la sentencia DO/END. Existen varias opciones para acompañar al DO:

DO WHILE
En este caso las sentencias entre el DO y el END se ejecutarán "mientras que" se cumpla una condición, es decir, mientras esa condición sea cierta.

DO WHILE CAMPO1 ¬= ' ';
sentencias a ejecutar;
END;


Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO WHILE (CAMPO1 ¬= ' ' & CAMPO2 = 1);
sentencias a ejecutar;
END;


DO UNTIL
En este caso las sentencias entre el DO y el END se ejecutarán "hasta que" se cumpla la condición especificada.

DO UNTIL CAMPO_ANO = 2012;
sentencias a ejecutar;
END;


Si tuviésemos más de una condición, deberá ir entre paréntesis.

DO + TO
En este caso las sentencias entre el DO y el END se ejecutarán hasta que se cumpla la condición especificada.

DO INDICE = 1 TO 10;
sentencias a ejecutar;
END;


Las sentencias a ejecutar se harán 10 veces (desde INDICE = 1 hasta 10, de 1 en 1).

Para retorcerlo un poco más podemos usar la sentencia BY:
DO INDICE = 1 TO 10 BY 2
sentencias a ejecutar;
END;


Las sentencias a ejecutar se harán 5 veces (desde INDICE = 1 hasta 10, de 2 en 2).

También se puede combinar el DO/TO con la opción WHILE:
DO INDICE = 1 TO 10 WHILE CAMPO1 = ' ';
sentencias a ejecutar;
END;

En este caso, además de controlar el valor de INDICE, la expresión del WHILE debe ser cierta.