jueves, 8 de septiembre de 2011

División entre enteros en PL/pgSQL

La división entre enteros elimina automáticamente la parte decimal del resultado. Esto puede ser contraproducente si necesitamos cálculos que hagan uso de la parte decimal, incluso si simplemente queremos redondear y obtener un entero, ya que obtendremos un resultado erróneo cuando la parte decimal sea mayor a 0.5. Consideremos por ejemplo que vamos a almacenar el valor del salario mensual de un contrato y queremos calcular el valor del día como valor entero y guardarlo para posteriores operaciones:

DECLARE
  ...
BEGIN
  ...
  NEW.salario_base_diario := NEW.salario_base_mensual / 30;


Si el salario_base_mensual es de 348, dividiendo en 30 obtendremos 11.6, al ser salario_base_diario entero esperaríamos tener un valor de 12, pero no. Postgres simplemente desprecia la parte decimal con lo que el valor que obtendremos será 11, lo cual puede generar muy malos resultados después. Para obtener un resultado adecuado es mejor almacenar una o varias de las variables usadas como tipo NUMERIC aunque sean enteros, de este modo el resultado será NUMERIC y podremos hacer el redondeo adecuado, así:

DECLARE
  ...
  var_nuevo_salario_base_mensual NUMERIC;
BEGIN
  ...
  -- Redondear el salario mensual a dos dígitos decimales
  var_nuevo_salario_base_mensual := round(NEW.salario_base_mensual, 2);
  NEW.salario_base_diario := round(var_nuevo_salario_base_mensual / cfg_dias_mes);


Con este pequeño cambio obtendremos lo que queremos, de modo que: 348/30 = 11.60. Y este resultado será redondeado correctamente a 12.