Now listening to…

16 julio \16\UTC 2017

Geoff Achison: Another mile, another minute.
Fischer-Z: Building bridges.
Samantha Fish: Chills & fever.
Dr.John: Locked down.

Saludos.

Carlos.


Máquina nueva (otra más)

14 julio \14\UTC 2017

Nueva máquina:

Dell Latitude 5580

Es un Dell Latitude 5580 que sustituirá al Dell Latitude E6540 que he venido utilizando los últimos años.

Si el anterior iba de fábula, éste es la bomba: intel i7 de séptima generación, 32GB RAM y un disco duro de estado sólido (SSD).

Además, viene con Windows 10, con lo que no me queda más remedio que aprenderme el nuevo entorno…

También he aprovechado para actualizarme con el VMware Player 12.5 (o como se llama ahora VMware Workstation Player). Un salto bastante grande, ya que me resistía a cambiar mi Player 6.02, que me funcionaba de maravilla. La migración ha ido muy bien y las máquinas virtuales corren mucho mejor ya que las he podido dar más recursos (sobre todo RAM). Hay que decir que las tribulaciones con el editor de redes virtuales (vmnetcfg.exe) se han reducido casi a cero, lo cual es de agradecer.

Como siempre: lots of fun to come…

Saludos.

Carlos.


Teradata Tools and Utilities (TTU’s) para Ubuntu

10 julio \10\UTC 2017

Hasta ahora las Teradata Teradata Tools and Utilities (TTU’s) para linux sólo se podían instalar “oficialmente” en distribuciones Redhat (y sus respectivas Fedora, CentOS, etc…) o en SuSE (también OpenSuSE). Este paquete de instalación está basado en paquetes “.rpm”.

A partir de la versión 16.10 aparece un nuevo paquete de instalación apto para Ubuntu (basado en paquetes “.deb”), con lo que las TTU’s pueden ser instaladas fácilmente en Ubuntu y, en teoría, en cualquier distribución basada en Debian.

Nota: De momento no pienso instalarlas en mi eee PC con Lubuntu. (Aunque, ¿quién sabe?…)

Saludos.

Carlos.

 

 


Lubuntu 16.04 en eee PC

3 julio \03\UTC 2017

El viejo eee PC que tenía La Parte Contraria andaba arrinconado por casa. El Windows 7 que traía como sistema operativo se había ido degradando hasta el punto de convertirlo prácticamente en inutilizable. El cacharro literalmente se arrastraba. Además, había sido olvidado tras la llegada de un nuevo chico más guapo: el iPad.

Así que, ¿qué se me ocurrió un domingo por la mañana? pues instalarle un Linux. Estuve mirando opciones, y tras descartar alternativas, me decidí por Lubuntu (y eso que no soy yo muy de Debian/Ubuntu…), pero tras investigar un poco, me pareció la mejor opción de entre todos los linux ligeros.

Primer asunto: el eee PC no tiene CD, por lo que hay que crear un USB ‘bootable‘. Y entrar en la BIOS para alterar el orden de arranque y que reconozca el USB como primera unidad. También necesité el ISO de Lubuntu 16.04, que me bajé de su “site“.

Para crear el USB ‘bootable‘ utilicé rufus, aunque no todo salió a la primera: los primeros intentos acabaron con repetidos “NO DEFAULT or UI configuration directive found.”. Aquí fue ensayo y error: diferentes versiones de rufus, cambios de USB y diferentes formateos (a mí me funcionó formatear con FAT16).

Tras por fin conseguir arrancar desde el USB comencé con la instalación. Pero todo fueron problemas (arrancar sin entorno gráfico, por ejemplo) que me hicieron tener que repetirla hasta tener éxito únicamente cuando hice la instalación con una conexión a internet abierta.

En esta instalación se accedía a los repositorios y se bajaban e instalaban versiones de los programas y librerías más actualizadas de las de la propia ISO.

Aunque, tras terminar por fin la descarga e instalación, al ir a hacer el primer “login” en la ventana de conexión, ésta volvía a aparecer una y otra vez sin que me dejara acceder al escritorio. Tras la consiguiente investigación (en init 3), descubrí que en el directorio “home” de mi usuario el fichero .Xauthority pertenecía a “root” y no a mí. “chown” al canto y a otra cosa.

Finalmente:

He de decir que estoy sorprendidísimo con el rendimiento. El cacharrín (un Atom con 1GB de RAM) va estupendamente bien. Nada que ver con la desesperante lentitud del Windows 7.

La navegación por internet va estupendamente (siempre y cuando no haya demasiado javascript) y en general el uso es magnífico (de hecho, estoy escribiendo esto con él). Incluso me atrevo con ‘pelis’ con el vlc que ni soñaría poder ver en el Windows.

Además, dispone de 250GB de disco duro y lector de tarjetas SD, y puede funcionar horas sólo con la batería. Creo que va a ser el accesorio ideal para las actividades fotográficas de las vacaciones de este verano, que me huelo yo que van a ser unas pocas…

En resumen: tengo juguete para una temporada…

Saludos.

Carlos.


Zapas Nuevas (y van…) 

31 marzo \31\UTC 2017

Zapas Nuevas: Mizuno Wave Inspire.

Mizuno Wave Inspire

Mizuno Wave Inspire

Segunda experiencia con unas Mizuno.

Saludos.

Carlos.


Ahí va ese bólido…

15 marzo \15\UTC 2017

Saludos.

Carlos.


NUMBERs, JOINs y ORs…

2 marzo \02\UTC 2017

Desde la versión 14, Teradata implementa el tipo “Oracle” NUMBER. Y lo hace a su imagen y semejanza: con el almacenamiento en forma de exponente y mantisa. El motivo es, principalmente, facilitar las migraciones desde Bases de Datos Oracle a Teradata (de las que he visto unas cuantas y he participado en otras). Anteriormente, al no disponer Teradata de un tipo análogo al NUMBER de Oracle, había que elegir entre los numéricos “nativos”, con las dificultades que ello conlleva y la propensión a errores por elecciones incorrectas.

El tipo en sí presenta ciertas ventajas y varias particularidades, como el espacio de almacenamiento variable (de 2 a 18 bytes), la posibilidad de variar escala y precisión sin modificar las filas o la precisión de 18 dígitos (o incluso más) en las operaciones con ellos. Por otra parte, es un tipo en coma flotante (floating point) que puede no ser todo lo exacto que necesitamos y puede llevar a pequeñas incorrecciones en los cálculos.

Así que, en teoría, no hay ningún problema para utilizar NUMBER(n, m) en Teradata tal como lo hacemos en Oracle, donde es el tipo numérico por excelencia.

Pero a veces las cosas no son lo que parecen:

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT * FROM DBC.DBCINFO;


 *** Query completed. 3 rows found. 2 columns returned.
 *** Total elapsed time was 1 second.

InfoKey                        InfoData
------------------------------ --------------------------------------
RELEASE                        15.10.02.01
VERSION                        15.10.02.03
LANGUAGE SUPPORT MODE          Standard

 BTEQ -- Enter your SQL request or BTEQ command:


CREATE MULTISET TABLE TESTDB.TEST1 (
   ID_C CHAR(2) NOT NULL,
   ID_N NUMBER
)
PRIMARY INDEX (ID_C);


 *** Table has been created.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:


INSERT INTO TESTDB.TEST1 VALUES ('98', 999999999999998);


 *** Insert completed. One row added.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO TESTDB.TEST1 VALUES ('99', 999999999999999);


 *** Insert completed. One row added.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:


CREATE MULTISET TABLE TESTDB.TEST2 (
   ID_C CHAR(2) NOT NULL,
   ID_N NUMBER(15, 0),
   C_TXT CHAR(6)
)
PRIMARY INDEX (ID_C);


 *** Table has been created.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:


INSERT INTO TESTDB.TEST2 VALUES ('98', 999999999999998, 'OCHO');


 *** Insert completed. One row added.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO TESTDB.TEST2 VALUES ('99', 999999999999999, 'NUEVE');


 *** Insert completed. One row added.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:


SELECT c.C_TXT
      ,a.ID_C
      ,a.ID_N
  FROM ( SELECT ID_C
               ,ID_N
          FROM TESTDB.TEST1
         WHERE ( ID_C = '98' AND
                 ID_N = 999999999999998 )
            OR ( ID_C = '99' AND
                 ID_N = 999999999999999 )
       ) a
  LEFT JOIN TESTDB.TEST2 c
         ON ( a.ID_C = c.ID_C
          AND a.ID_N = c.ID_N )
;


 *** Query completed. 2 rows found. 3 columns returned.
 *** Total elapsed time was 1 second.

C_TXT   ID_C                                      ID_N
------  ----  ----------------------------------------
(null)  99                             999999999999999
OCHO    98                             999999999999998

 BTEQ -- Enter your SQL request or BTEQ command:


SELECT c.C_TXT
      ,a.ID_C
      ,a.ID_N
  FROM ( SELECT ID_C
               ,ID_N
          FROM TESTDB.TEST1
         WHERE ( ID_C = '99' AND
                 ID_N = 999999999999999 )
            OR ( ID_C = '98' AND
                 ID_N = 999999999999998 )
       ) a
  LEFT JOIN TESTDB.TEST2 c
         ON ( a.ID_C = c.ID_C
          AND a.ID_N = c.ID_N )
;


 *** Query completed. 2 rows found. 3 columns returned.
 *** Total elapsed time was 1 second.

C_TXT   ID_C                                      ID_N
------  ----  ----------------------------------------
(null)  98                             999999999999998
NUEVE   99                             999999999999999

 BTEQ -- Enter your SQL request or BTEQ command:

Como podemos ver, la misma query da resultados diferentes sólo con cambiar el orden de los filtros en la parte WHERE … OR de la subselect “a”.

¡Pero eso es imposible! Todos sabemos que el ‘OR’ es conmutativo.

Además, ambos resultados son erróneos.

¿Y qué puede causar este comportamiento? Pues, presumiblemente, los resultados intermedios de la subselect “a” varían en cuanto al tipo elegido según lleguen las primeras filas como 999999999999998 ó 999999999999999. El tipo definido para ID_N en TEST1 es NUMBER, sin especificar escala ni precisión, mientras que en TEST2 es NUMBER(15, 0). Aunque externamente “NUMBER es NUMBER”, en algún lugar se producen diferencias que hacen que el JOIN no funcione como se espera.

Por eso, si estamos en lo cierto, al hacer un CAST explícito sobre las columnas NUMBER en la subselect todo debería funcionar OK:

SELECT c.C_TXT
      ,a.ID_C
      ,a.ID_N
  FROM ( SELECT ID_C
               ,ID_N (NUMBER(15,0))  --CAST!!
          FROM TESTDB.TEST1
         WHERE ( ID_C = '98' AND
                 ID_N = 999999999999998 )
            OR ( ID_C = '99' AND
                 ID_N = 999999999999999 )
       ) a
  LEFT JOIN TESTDB.TEST2 c
         ON ( a.ID_C = c.ID_C
          AND a.ID_N = c.ID_N )
;


 *** Query completed. 2 rows found. 3 columns returned.
 *** Total elapsed time was 1 second.

C_TXT   ID_C              ID_N
------  ----  ----------------
NUEVE   99     999999999999999
OCHO    98     999999999999998

 BTEQ -- Enter your SQL request or BTEQ command:


SELECT c.C_TXT
      ,a.ID_C
      ,a.ID_N
  FROM ( SELECT ID_C
               ,ID_N (NUMBER(15,0))  --CAST!!
          FROM TESTDB.TEST1
         WHERE ( ID_C = '99' AND
                 ID_N = 999999999999999 )
            OR ( ID_C = '98' AND
                 ID_N = 999999999999998 )
       ) a
  LEFT JOIN TESTDB.TEST2 c
         ON ( a.ID_C = c.ID_C
          AND a.ID_N = c.ID_N )
;


 *** Query completed. 2 rows found. 3 columns returned.
 *** Total elapsed time was 1 second.

C_TXT   ID_C              ID_N
------  ----  ----------------
NUEVE   99     999999999999999
OCHO    98     999999999999998

 BTEQ -- Enter your SQL request or BTEQ command:

En efecto, vemos que con CAST explícito todo vuelve a la normalidad y la SELECT da el resultado esperado (y correcto esta vez).

Claro que esto no deja de ser un “workaround“. Supongo que alguien tiene trabajo en Rancho Bernardo.

Por otra parte, siempre se debería especificar escala y precisión en los tipos NUMBER (en Oracle también).

Saludos.

Carlos.