lunes, 31 de enero de 2011

Número Relativo en SQL 400 ((Monitorear Error de Datos Decimales)

Hay tablas que por diversos motivos contienen datos numéricos inválidos, mayormente, producto de una mala copia (CPYF). Y al procesarlos el sistema nos muestra ese mensaje que ya todos conocemos: “Error de datos decimales.”
Si usas Rgp Ile podemos monitorear automáticamente dicha excepción en el momento de compilar el programa, colocando en el parámetro FIXNBR (Arreglar numérico) los valores *ZONED y *INPUTPACKED, con eso los datos numéricos no válidos se trataran como ceros.
La información que nos muestra el sistema respecto al registro con dato numérico inválido es el número de registro relativo del archivo. Esto lo podemos obtener visualizando el trabajo, ya sea interactivo o por lotes, con la opción 14 del comando DSPJOB .
DSPJOB JOB(866190/MIUSUARIO/QPADEV004K) 

                               Visualizar Trabajo                              
                                                            Sistema:   PUB1    
 Trabajo:   QPADEV004K     Usuario:   MIUSUARIO       Número:   866190          
                                                                               
 Seleccione una de las opciones siguientes:                                    
                                                                                
      1. Visualizar atributos de estado de trabajo                             
      2. Visualizar atributos de definición de trabajo                         
      3. Visualizar atributos de ejecución de trabajo, si está activo          
      4. Visualizar archivos en spool                                          
                                                                               
     10. Visualizar anotaciones trabajo, si está activo o en cola de trabajos  
     11. Visualizar pila de llamadas, si está activo                           
     12. Visualizar bloqueos, si está activo                                   
     13. Visualizar lista de bibliotecas, si está activo                       
     14. Visualizar archivos abiertos, si está activo                          
     15. Visualizar alteraciones temporales de archivo, si está activo         
     16. Visualizar estado de control de compromiso, si está activo            
                                                                         Más...
 Selección                                                                     
                                                                                
                                                                               
 F3=Salir   F12=Cancelar                                                       
                                                                               

Esta opción nos permite visualizar los archivos que el sistema utiliza en dicho trabajo.
En la pantalla “Visualizar Archivos Abiertos” pulsando F11 (Visual. detalles E/S) podremos descubrir el numero relativo del registro que tiene problemas.

                              Visualizar Archivos Abiertos                     
                                                                               
 Trabajo :   QPADEV004K     Usuario  :   MIUSUARIO       Número . . . :   866190
 Número de vías de datos abiertas  . . . . . . :      6                        
                                                                               
                                                                               
                       Miembro/   Formato    Tipo   Núm.  -Abiertos--  Registro
 Archivo    Bibliot.   disposit.  registro   arch.  E/S   Opc Núm-cmp  relativo
 QDSPMNU    QSYS2931   QPADEV004K MENULY     DSP        2 IO  NO               
 QDUODSPF   QSYS2931   QPADEV004K MSGSFC     DSP      500 IO  NO               
 QDDSPEXT   QSYS2931   *N         INQFMT     DSP      161 IO  NO               
 ARCHIVO1   MIUSUARIO  ARCHIVO1   REGFILE1   PHY        1 I   NO              3
 QDUI132    QSYS2931   QPADEV004K USRRCD     DSP        4 IO  NO               
 QDDSPOF    QSYS2931   QPADEV004K DETAIL2    DSP       16 IO  NO               
                                                                               
                                                                                
                                                                               
                                                                               
                                                                                
                                                                          Final
 Pulse Intro para continuar.                                                   
                                                                                
 F3=Salir  F5=Renovar   F11=Visual. datos ámbito   F12=Cancelar F16=Menú trabajo
                                                                               

Si estamos hablando de un archivo sin claves, el DFU nos permite ubicar el registro por numero relativo, pulsando la tecla F11. Luego colocamos el numero relativo del registro

*RECNBR:           3 

Pero no podremos modificar el dato del registro, puesto que la información no podrá visualizarse en la pantalla, mostrandose el mensaje “El registro recuperado contiene datos no válidos.” 

Yo utilizo la función RRN del SQL.
En nuestro ejemplo el error esta en el registro relativo 3, vamos al SQL y seleccionamos dicho registro de la siguiente manera:
SELECT *  FROM MILIBRERIA/ARCHIVO1 WHERE RRN(ARCHIVO1) = 3
O si deseamos podremos ver todos los registros y a la vez el numero relativo al que pertenecen.
SELECT RRN(ARCHIVO1), CAMPO1, CAMPO2, CAMPO3 FROM MIUSUARIO/ARCHIVO1  

....+....1....+....2....+....3....+....4....+....5....+....6....     
   RRN ( ARCHIVO1 )   CAMPO1  CAMPO2                     CAMPO3      
                  1     111   CRISTIAN                   150.00      
                  2     222   SERGIO                      56.22      
                  3     100   01FISICOQUIMICA  +++++++++++++++++     
                  4     100   02FISICA IV      +++++++++++++++++     
                  5     100   03BIOLOGIA       +++++++++++++++++     
********  Fin de datos  ********                                     
                                                                     
Si se tratase de un archivo que contiene varios datos numéricos, con esta función podrás identificar que dato presenta el problema.
Luego de identificar el problema puedes utilizar un poderoso UPDATE para modificar el dato con el valor correcto.  Por ejemplo:

UPDATE MIUSUARIO/ARCHIVO1 SET CAMPO3 = 50.25 WHERE RRN(ARCHIVO1) = 3


Esta función es muy útil, no solo para detectar inconsistencia de información sino para el manejo de la información de los archivos. Espero te sirva de mucha utilidad. Nos vemos.

domingo, 30 de enero de 2011

Fecha Juliana en Cobol AS400 (Format Date)

Las bases de datos de nuestros sistemas guardan la información referente a fechas en formatos que no originen errores de cálculos en lo que se refiere a diferencias de fecha, duración, etc.
Comúnmente registran esos datos en el formato siguiente: AAAAMMDD. Pero hay sistemas en que almacenan dicha información en formato juliano, es decir AAAADDD, donde DDD equivale al número de día del año desde 1 al 365 (366 en caso de año bisiesto)  AAAA es el año.
Y a veces nos vemos en la necesidad de presentar esta información en formato más amigable para el usuario, ya sea en reportes o pantallas. O sea algo asi: DD/MM/AAAA.
En esta oportunidad voy a aplicar la conversión de dichos formatos a su equivalente en DDMMAAAA aplicándolo al lenguaje cobol. Muchas veces esto lo solucionan preparando programas adicionales (rutinas) para que devuelva su equivalencia a otro formato. Es aceptable, pero no muy beneficioso si el programa invoca la misma rutina por cada campo que contenga una fecha y hacerlo también por cada registro del archivo. Recuerda que al invocar programas externos (rutinas) es decirle al sistema que busque el programa en la lista de librerías de job y luego ejecutarlo. Hacer eso por cada invocación no resulta favorable en la performance de nuestro programa.
Les recomendaría hacer uso de las funciones integradas del ILE. Para cobol ile existe una declaración del formato de variable de tipo fecha. También la hay para la Hora. Pero bastará aplicar un ejemplo para la primera para darnos cuenta de su utilidad.
Aquí les muestro un ejemplo sencillo de cómo realizar la conversión de formatos de fechas.
WORKING-STORAGE SECTION.                            
77  Fec-Eur               Format Date  "%d%m@Y".    
77  Fec-Iso               Format Date  "@Y%m%d".    
77  Fec-Jul               Format Date  "@Y%j".      
77  Var-Fecha-Archivo     Pic 9(8) Value 20110129.  
                                                   
                                                     
PROCEDURE DIVISION.                                 
INICIO.                                             
    If    Var-Fecha-Archivo is greater than zeros   
          Move   Var-Fecha-Archivo        to  Fec-Iso
          Move   Fec-Iso                  to  Fec-Eur
          Move   Fec-Eur                  to  Fec-Jul
    End-If                                          
    Display "En formato Eur..... "  Fec-Eur.        
    Display "En formato Juliano. "  Fec-Jul.        
                                                     
    STOP RUN.                                       
Hago la consistencia del campo del archivo (Var-Fecha-Archivo) porque si este dato contiene ceros, al asignarle ceros a una variable tipo fecha, el sistema no reconoce la fecha y con ellos arroja error. Puedes enterarte de los diferentes formatos de fecha que maneja el ile en el website de IBM.

martes, 25 de enero de 2011

Comparar Tablas (Registros NO Coincidentes) EXCEPTION JOIN SQL/400

0Cuántas veces hemos querido comparar 2 tablas, saber que registros de una tabla NO están en la otra y viceversa. Puedes hacer un programa, generando el resultado en otra tabla o en un reporte, pero eso te toma un tiempo. O también puedes hacer un Query.
Algo muy práctico para hacer esto resulta usar la sentencia SELECT del SQL.
Sino estas muy familiarizado con el estándar ANSI (LEFT JOIN, RIGHT JOIN) puedes recurrir a la clausula EXCEPTION JOIN. Personalmente yo uso esta última alternativa.

SELECT A.*, B.*
FROM MILIBRERIA/ARCHIVO1 A EXCEPTION JOIN MILIBRERIA/ARCHIVO2 B
ON A.CAMPO1 = B.CAMPO1

Situar en línea  . . . . . .                                
....+....1....+....2....+....3....+....4....+....5....+....6.
CAMPO1  CAMPO2                     CAMPO3   CAMPO1  CAMPO2  
  111   Jose Vasquez                15.00        -  -       
  222   Edwin Sanchez                5.00        -  -       
********  Fin de datos  ********                            


En este ejemplo, la clausula EXCEPTION JOIN muestra como resultado los registros de la tabla ARCHIVO1 que NO se encuentran en la tabla ARCHIVO2.  Y como estamos seleccionando los campos de ambas tablas, los registros de la tabla ARCHIVO2 se muestran en NULL.

Ahora mostremos los registros de ARCHIVO2 que no están en ARCHIVO1

SELECT A.*, B.*                                                 
FROM MILIBRERIA/ARCHIVO2 B EXCEPTION JOIN MILIBRERIA/ARCHIVO1 A
ON  B.CAMPO1 = A.CAMPO1  
 
Situar en línea  . . . . . .                                       
....+....1....+....2....+....3....+....4....+....5....+....6....+...
CAMPO1  CAMPO2                     CAMPO3   CAMPO1  CAMPO2         
     -  -                                -    333   Sergio Gonzales
     -  -                                -    444   Cesar Ramirez  
********  Fin de datos  ********                                   

  

La tabla que se declara a la izquierda de la clausula EXCEPTION JOIN es la tabla primaria, es decir, la tabla que contiene los registros que NO se encuentren en la tabla de la derecha.
Si deseamos tener los registros que NO estén en ambas tablas, o sea, los registros no COINCIDENTES entre ambas tablas, solo nos basta unir ambas sentencias SELECT con la clausula UNION

SELECT A.*, B.*
FROM MILIBRERIA/ARCHIVO1 A EXCEPTION JOIN MILIBRERIA/ARCHIVO2 B
ON A.CAMPO1 = B.CAMPO1
UNION
SELECT A.*, B.*                                                 
FROM MILIBRERIA/ARCHIVO2 B EXCEPTION JOIN MILIBRERIA/ARCHIVO1 A
ON  B.CAMPO1 = A.CAMPO1 

Situar en línea  . . . . . .                                       
....+....1....+....2....+....3....+....4....+....5....+....6....+...
CAMPO1  CAMPO2                     CAMPO3   CAMPO1  CAMPO2         
  111   Jose Vasquez                15.00        -  -              
  222   Edwin Sanchez                5.00        -  -              
     -  -                                -    333   Sergio Gonzales
     -  -                                -    444   Cesar Ramirez  
********  Fin de datos  ********                                   




Nota: En la clausula ON puedes indicar los campos que desees comparar, adicionalmente puedes considerar condiciones en la clausula WHERE.
El INNER JOIN te recupera los registros coincidentes entre ambas tablas

lunes, 24 de enero de 2011

Mover de Registro a Registro - RPG (ExtName)

A veces nos hemos visto en la situación de hacer un programa que trabaje 2 tablas (archivos) con la misma estructura (mismo formato de registro y campos)  tenemos que modificar unos datos en la primera tabla y grabar las modificaciones en la segunda tabla. Y nos vemos con la necesidad de mover campo por campo a la segunda tabla. Buscamos en internet y como casi siempre es urgente hacemos las cosas mas simples pero laboriosas a la vez.
Si la tabla contiene pocos campos eso no es ningún problema, pero si hablamos de una tabla con mas de 20 campos resulta algo muy tedioso y hace engorroso nuestro código.
En cobol es realmente fácil hacerlo, solo es mover un registro al otro y listo.

DATA DIVISION.                           
 FILE SECTION.                           
01 REG-FILE1.                             
     COPY DDS-ALL-FORMATS OF ARCHIVO1.   
01 REG-FILE2.                            
     COPY DDS-ALL-FORMATS OF ARCHIVO2.   
...                                      
                                         
MOVE REG-FILE1 TO REG-FILE2              
WRITE  REG-FILE2                          

Pero… y en RPG???
Tienes varias opciones:
1.- Declaras la primera tabla con la hoja I, para la segunda tabla la Hoja O y haces uso del código de operación EXCEPT para grabar.
2.- O haces un SQL, haces el cálculo en los campos y  derivas el resultado a la segunda tabla. Pero si las modificaciones son muy complejas? Accesando a otra tabla por ejemplo? Se hace complicado.
Yo hago uso de las “bondades” del ILE.  Aquí un ejemplo sencillo pero útil.


farchivo1  ip   e             disk                                        
farchivo2  o  a e             disk    rename(regfile1:reg) prefix(x)      
 * declaracion Estructura de Datos Externa                                
d reg1          e ds                  extname(archivo1)                   
d reg2          e ds                  extname(archivo2) prefix(x)         
 * calculo                                                                
c                   eval      campo3 = campo3 + 2.85                      
 * mueve todo el registro                                                 
c                   move      reg1          reg2                          
 * graba el registro                                                      
c                   write     reg                                         


Pueden encontrar mas detalles de la palabra clave EXTNAME en los muchos tutoriales que encontramos en internet, pero la finalidad de esta demostración es su aplicación a los problemas que se nos presentan diariamente y que mayormente no damos la solución mas eficiente o idonea por falta de tiempo o porque no la encontramos oportunamente. Espero les haya servido y les sea de gran utilidad. Saludos.