ROUND() y TRUNC() para valores numéricos en Teradata.

A menudo encuentro consultas -principalmente de gente con experiencia en Oracle- acerca de la existencia de las funciones ROUND() y TRUNC() para valores numéricos en Teradata. Cierto. Una vez más, una larga exposición a Oracle hace que se instale en nuestro cerebro la forma ‘Oracle’ de hacer las cosas en SQL, sin pararnos a pensar que eso no es el estándar y que hay otras maneras -ni mejores ni peores, sólo distintas- de hacer lo mismo en cualquier otro SGBDR (ya hemos visto aquí cosas semejantes para funciones LAG/LEAD y LPAD/RPAD.).

Oracle utiliza las funciones ROUND() y TRUNC() para el manejo de los remanentes en el caso de pérdida de precisión en conversiones de números.

Veamos primero ROUND()

ROUND ( n, integer)

ROUND returns n rounded to integer places to the right of the decimal point. If you omit integer, then n is rounded to 0 places. The argument integer can be negative to round off digits left of the decimal point.

En efecto: basta con decirle el número de decimales y Oracle se encarga del resto:

CARLOS@XE.localhost> select round(12.34, 1) from dual;

ROUND(12.34,1)
--------------
          12,3

CARLOS@XE.localhost> select round(12.36, 1) from dual;

ROUND(12.36,1)
--------------
          12,4

Ya. Pero en Teradata no existe tal función. ¿Qué hacemos, pues?

Pues nos acordamos de que en Teradata todas las pérdidas de precisión (excepto una (*)) se realizan con redondeo (ROUND):

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT CAST(12.34 AS DECIMAL(4,1));

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

 12.34
------
  12.3

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT CAST(12.36 AS DECIMAL(4,1));

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

 12.36
------
  12.4

Los más avispados se habrán dado cuenta de que en los números del ejemplo no se ha utilizado el ‘12.35’. Para Oracle, si la cantidad a la derecha (remanente) del dígito a redondear es ‘5’ se produce un redondeo hacia arriba:

CARLOS@XE.localhost> select round(12.35, 1) from dual;

ROUND(12.35,1)
--------------
          12,4

CARLOS@XE.localhost> select round(12.345, 2) from dual;

ROUND(12.345,2)
---------------
          12,35

El tema del redondeo para cuando ‘5’ es el remanente a redondear es más complejo de lo que parece en Teradata, y aun podríamos decir ‘caprichoso’. Primero, porque depende del valor que haya en el RoundHalfwayMagUp del DBS Control Record. Para el valor por defecto (‘FALSE’) el redondeo se produce de la siguiente manera:

Si el valor a la derecha del último dígito de redondeo (remanente) es ‘5’, entonces:

·Si el último digito a redondear es par, se incrementa en uno.
·Si el último digito a redondear es impar, se queda como está.

Esto nos lleva a resultados tan sorprendentes como que :

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.005 as decimal(3,2));

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

 .005
-----
  .00

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.015 as decimal(3,2));

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

 .015
-----
  .02

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.025 as decimal(3,2));

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

 .025
-----
  .02

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.035 as decimal(3,2));

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

 .035
-----
  .04

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.045 as decimal(3,2));

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

 .045
-----
  .04

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.055 as decimal(3,2));

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

 .055
-----
  .06

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (.065 as decimal(3,2));

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

 .065
-----
  .06

Ya lo sé, ya lo sé. A mí tampoco me gusta, pero es lo que hay…

Ahora veamos TRUNC():

Al igual que ROUND(), TRUNC() en Oracle no necesita mucha explicación:

TRUNC ( n1, n2)

Purpose
The TRUNC (number) function returns n1 truncated to n2 decimal places. If n2 is omitted, then n1 is truncated to 0 places. n2 can be negative to truncate (make zero) n2 digits left of the decimal point.

CARLOS@XE.localhost> select trunc(123.456, 2) from dual;

TRUNC(123.456,2)
----------------
          123,45

CARLOS@XE.localhost> select trunc(123.456, 1) from dual;

TRUNC(123.456,1)
----------------
           123,4

Para conseguir lo mismo, en Teradata nos vamos a aprovechar de que la conversión de tipos a enteros es la excepción de la que hablábamos al principio (*).

Así pues, multiplicar, convertir y volver a convertir nos vale para obtener los mismos resultados:

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (123.456*100 as integer)/100.00;

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

((123.456*100)/100.00)
----------------------
                123.45

 BTEQ -- Enter your SQL request or BTEQ command:
select cast (123.456*10 as integer)/10.0;

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

((123.456*10)/10.0)
-------------------
              123.4

Hay otras formas de conseguirlo, como jugar con el cociente y el resto de divisiones por múltiplos de 10, y la verdad es que bonito, lo que se dice bonito, no es. Pero funciona.

Nota: A partir de Teradata 14, puedes (y yo diría que debes) utilizar las funciones nativas ROUND() y TRUNC(), como se explica aquí.

Saludos.

Carlos.

Una respuesta a ROUND() y TRUNC() para valores numéricos en Teradata.

  1. […] ahora, el redondeo y truncado de datos numéricos en Teradata se venía haciendo utilizando cambios de tipo (CASTs) aprovechando el tratamiento de la pérdida de […]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: