Convertir BYTE a entero (“unsigned smallint”) en Teradata.

Supongamos que queremos convertir datos de typo BYTE(2) a su valor entero. Lo primero que pensamos es en algo así como:

BTEQ -- Enter your SQL request or BTEQ command:
SELECT CAST(('327D'XB) AS INTEGER);

*** Failure 3532 Conversion between BYTE data and other types is illegal.
               Statement# 1, Info =0
*** Total elapsed time was 1 second.

Error. En Teradata los typos BYTE son bastante puñeteros, y no permiten la conversión de tipos en ninguna circunstancia (Esto es una máxima en Teradata).

Entonces ¿qué hacemos si queremos convertir un valor BYTE a su entero correspondiente? Pues que deberemos, como siempre, hacer trampas.

Teradata basa su paralelismo y su necesaria distribución de los datos en unas funciones de ‘hashing‘ que son las encargadas de distribuir las filas en los AMPs basándose en los valores de las columnas definidas en los ‘primary indexes‘. Además ofrece al usuario tres funciones de utilidad para poder analizar dicha distribución: HASHROW, HASHBUCKET y HASHAMP. Normalmente se utilizan juntas, ya que la salida de una suele ser la entrada de la otra:

SELECT HASHAMP(HASHBUCKET(HASHROW('A')));

 *** Query completed. One row found. One column returned.
 *** Total elapsed time was 1 second.

HASHAMP(HASHBUCKET(HASHROW('A')))
---------------------------------
                                4

Esto quiere decir que si tuviéramos una tabla cuyo ‘primary index‘ fuese una columna CHAR(1), una fila cuyo valor para esa columna fuese ‘A’ estaría localizada en el AMP número 4 (esto depende de la configuración de cada sistema y sería algo largo explicar aquí todo el mecanismo, el que quiera puede repasarse la documentación).

Nosotros nos vamos a centrar en la segunda función “HASHBUCKET”, que recibe un BYTE(4) como resultado de la salida de “HASHROW” y devuelve un entero de cuatro bytes. Los dos primeros bytes se llaman DSW (‘destination selection word‘) y aquí viene el truco: esta DSW no es más que un valor entre 0 y 65535 que se utilizará luego en el “HASHMAP”, pero esa es otra historia…

El caso es que si tenemos un valor de hasta 2 bytes (’1A9F’, por ejemplo) podemos resolver su valor entero haciendo esto:

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT HASHBUCKET('1A9F0000'XB);

 *** Query completed. One row found. One column returned.
 *** Total elapsed time was 1 second.

HASHBUCKET('1A9F0000'XB)
------------------------
                    6815

Y devuelve 6815 que es, efectivamente, el valor entero de ’1A9F’.

Nótese que hemos tenido que rellenar a ceros hasta conseguir un BYTE(4), que es lo que pide HASHBUCKET(), pero nos permite un ‘CAST’ que de otra manera está prohibido.

Pero aún podemos ir un poco más lejos:

 BTEQ -- Enter your SQL request or BTEQ command:
CREATE TABLE MY_DB.PRUEBA01(ID_N INTEGER NOT NULL,
                            B_N2 BYTE(2) NOT NULL
                            )
       UNIQUE PRIMARY INDEX (ID_N)
;

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

 BTEQ -- Enter your SQL request or BTEQ command:

INSERT INTO MY_DB.PRUEBA01(ID_N, B_N2) VALUES (1, '0001'XB);

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

 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO MY_DB.PRUEBA01(ID_N, B_N2) VALUES (2, '0002'XB);

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

 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO MY_DB.PRUEBA01(ID_N, B_N2) VALUES (10, '000A'XB);

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

 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO MY_DB.PRUEBA01(ID_N, B_N2) VALUES (255, '00FF'XB);

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

 BTEQ -- Enter your SQL request or BTEQ command:
INSERT INTO MY_DB.PRUEBA01(ID_N, B_N2) VALUES (65535, 'FFFF'XB);

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

 BTEQ -- Enter your SQL request or BTEQ command:

SELECT * FROM MY_DB.PRUEBA01 ORDER BY 1
;

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

       ID_N  B_N2
-----------  ----
          1  0001
          2  0002
         10  000A
        255  00FF
      65535  FFFF

Tenemos una tabla con valores BYTE(2) y sus enteros correspondientes (sólo a efectos de demostración).

Podemos entonces convertir los BYTE(2) a enteros entre 0 y 65535 haciendo:

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT ID_N, B_N2, HASHBUCKET(B_N2||'0000'XB)
  FROM MY_DB.PRUEBA01
 ORDER BY 1;

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

       ID_N  B_N2  HASHBUCKET((B_N2||'0000'XB))
-----------  ----  ----------------------------
          1  0001                             1
          2  0002                             2
         10  000A                            10
        255  00FF                           255
      65535  FFFF                         65535

et voilà! Aprovechando que podemos ‘concatenar bytes’ utilizando la expresión “||’0000′XB”, conseguimos rellenar a ceros los dos bytes restantes que espera “HASHBUCKET” y realizar la conversión prohibida.

Saludos.

Carlos.

Advertisement

Una Respuesta a Convertir BYTE a entero (“unsigned smallint”) en Teradata.

  1. [...] viendo claro. Sólamente con conocer como funciona SUBSTR() con datos tipo ‘BYTE’ y cómo convertir estos datos a ‘INTEGERs’ podemos hacer la [...]

Deja un comentario

Fill in your details below or click an icon to log in:

Logo de WordPress.com

You are commenting using your WordPress.com account. Log Out / Cambiar )

Twitter picture

You are commenting using your Twitter account. Log Out / Cambiar )

Facebook photo

You are commenting using your Facebook account. Log Out / Cambiar )

Connecting to %s

Seguir

Get every new post delivered to your Inbox.