domingo, 29 de agosto de 2010

PostgreSQL: Funcion que convierte un numero a texto

La siguiente funcion esta escrita en plpgsql y retorna un cadena de texto correspondiente a un numero que se pasa por parametro, la funcion devuelve hasta un maximo de 999999999,99
Esta funcion la saque de un foro hace un tiempo ya, la tenia en alguna BD de prueba y para no perderla... pues la coloco aqui..

-- DROP FUNCTION f_convnl(numeric);

CREATE OR REPLACE FUNCTION f_convnl(num numeric)
  RETURNS character varying AS
$BODY$
-- Función que devuelve la cadena de texto en castellano que corresponde a un número.
-- Parámetros: número con 2 decimales, máximo 999999999,99.

 
DECLARE 
 d VARCHAR[];
 f VARCHAR[];

 g VARCHAR[];
 numt VARCHAR;
 txt VARCHAR;

 a INTEGER;
 a1 INTEGER;
 a2 INTEGER;
 n INTEGER;

 p INTEGER;
 negativo BOOLEAN;
BEGIN
 -- Máximo 999.999.999,99

 IF num > 999999999.99 THEN
  RETURN '---';

 END IF;
 txt = '';
 d = ARRAY[' un',' dos',' tres',' cuatro',' cinco',' seis',' siete',' ocho',' nueve',' diez',' once',' doce',' trece',' catorce',' quince',

  ' dieciseis',' diecisiete',' dieciocho',' diecinueve',' veinte',' veintiun',' veintidos', ' veintitres', ' veinticuatro', ' veinticinco',

  ' veintiseis',' veintisiete',' veintiocho',' veintinueve'];

 f = ARRAY ['','',' treinta',' cuarenta',' cincuenta',' sesenta',' setenta',' ochenta', ' noventa'];

 g= ARRAY [' ciento',' doscientos',' trescientos',' cuatrocientos',' quinientos',' seiscientos',' setecientos',' ochocientos',' novecientos'];

 numt = LPAD((num::numeric(12,2))::text,12,'0');

 IF strpos(numt,'-') > 0 THEN

    negativo = TRUE;
 ELSE
    negativo = FALSE;

 END IF;
 numt = TRANSLATE(numt,'-','0');

 numt = TRANSLATE(numt,'.,','');

 -- Trato 4 grupos: millones, miles, unidades y decimales
 p = 1;
 FOR i IN 1..4 LOOP

  IF i < 4 THEN
   n = substring(numt::text FROM p FOR 3);

  ELSE
   n = substring(numt::text FROM p FOR 2);

  END IF;
  p = p + 3;
  IF i = 4 THEN

   IF txt = '' THEN
    txt = ' cero';

   END IF;
   IF n > 0 THEN
   -- Empieza con los decimales

    txt = txt || ' con';
   END IF;

  END IF;
  -- Centenas 
  IF n > 99 THEN

   a = substring(n::text FROM 1 FOR 1);

   a1 = substring(n::text FROM 2 FOR 2);

   IF a = 1 THEN
    IF a1 = 0 THEN

     txt = txt || ' cien';
    ELSE
     txt = txt || ' ciento';

    END IF;
   ELSE
    txt = txt || g[a];

   END IF;
  ELSE
   a1 = n;
  END IF;

  -- Decenas
  a = a1;
  IF a > 0 THEN

   IF a < 30 THEN
    IF a = 21 AND (i = 3 OR i = 4) THEN

     txt = txt || ' veintiuno';
    ELSIF n = 1 AND i = 2 THEN

     txt = txt; 
    ELSIF a = 1 AND (i = 3 OR i = 4)THEN

     txt = txt || ' uno';
    ELSE
     txt = txt || d[a];

    END IF;
   ELSE
    a1 = substring(a::text FROM 1 FOR 1);

    a2 = substring(a::text FROM 2 FOR 1);

    IF a2 = 1 AND (i = 3 OR i = 4) THEN

      txt = txt || f[a1] || ' y' || ' uno';

    ELSE
     IF a2 <> 0 THEN
      txt = txt || f[a1] || ' y' || d[a2];

     ELSE
      txt = txt || f[a1];
     END IF;

    END IF;
   END IF;
  END IF;

  IF n > 0 THEN
   IF i = 1 THEN

    IF n = 1 THEN
     txt = txt || ' millón';

    ELSE
     txt = txt || ' millones';
    END IF;

   ELSIF i = 2 THEN
    txt = txt || ' mil';

   END IF;  
  END IF;
 END LOOP;

 txt = LTRIM(txt);
 IF negativo = TRUE THEN

    txt= '-' || txt;
 END IF;
    RETURN txt;

END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;
ALTER FUNCTION f_convnl(numeric) OWNER TO u_test;

1 comentario: