Obtendo número por extenso com TO_CHAR

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
  

Mensagemem Qui, 27 Mai 2004 10:08 pm

Vejam que interessante:
Existe um formato de data que é representado por números. Daí, pedimos para o Oracle nos mostrar essa data "por extenso". Como resultado, podemos usar esta função nativa para traduzir números para extenso.

Código: Selecionar todos
dbglufke:SCOTT> select to_char( to_date( 123456, 'J'), 'jsp') from dual
  2  /

TO_CHAR(TO_DATE(123456,'J'),'JSP')
--------------------------------------------------------
one hundred twenty-three thousand four hundred fifty-six

dbglufke:SCOTT>


Desvantagens:
* só funciona em ingles... Não adianta mudar o LANG
* não aceita decimais
* não aceita números muito grandes....

Em resumo, este post vai mais a título de curiosidade...
dr_gori
Localização: Portland, OR USA

Thomas F. G

Você já respondeu a dúvida de alguém hoje?
http://glufke.net/oracle/search.php?search_id=unanswered

Mensagemem Sex, 20 Ago 2004 11:42 am

Não é que o Tom Kyte (meu xará), aprimorou essa "deficiência" de números grandes???
Veja a função abaixo:

Código: Selecionar todos
create or replace
function spell_number( p_number in number )
return varchar2
as
type myArray is table of varchar2(255);
l_str myArray := myArray( '',
' thousand ', ' million ',
' billion ', ' trillion ',
' quadrillion ', ' quintillion ',
' sextillion ', ' septillion ',
' octillion ', ' nonillion ',
' decillion ', ' undecillion ',
' duodecillion ' );

l_num varchar2(50) default trunc( p_number );
l_return varchar2(4000);
begin
for i in 1 .. l_str.count
loop
exit when l_num is null;

if ( substr(l_num, length(l_num)-2, 3) <> 0 )
then
l_return := to_char(
to_date(
substr(l_num, length(l_num)-2, 3),
'J' ),
'Jsp' ) || l_str(i) || l_return;
end if;
l_num := substr( l_num, 1, length(l_num)-3 );
end loop;

return l_return;
end;
/



Vamos testar:
Código: Selecionar todos
SQL> select spell_number(1234567890) from dual;

SPELL_NUMBER(1234567890)
--------------------------------------------------------
One billion Two Hundred Thirty-Four million Five
Hundred Sixty-Seven thousand Eight Hundred Ninety

SQL>
dr_gori
Localização: Portland, OR USA

Thomas F. G

Você já respondeu a dúvida de alguém hoje?
http://glufke.net/oracle/search.php?search_id=unanswered

Mensagemem Sex, 10 Fev 2006 11:15 am

Dr.

Precisei usar o extenso em português numa aplicação minha.
Usando alguns exemplos de outras linguagens, desenvolvi o seguinte:

Código: Selecionar todos
create or replace function extenso_monetario ( valor number ) return varchar2 IS
valor_string varchar2( 256 );
valor_conv VARCHAR2(25);
ind NUMBER;
tres_digitos VARCHAR2(3);
texto_string varchar2(256);
begin
  valor_conv := to_char( trunc((abs(valor) * 100),0) , '0999999999999999999' );
  valor_conv := substr( valor_conv , 1 , 18 ) || '0' || substr( valor_conv , 19, 2 );
  if to_number( valor_conv ) = 0 then
    return( 'Zero ' );
  end if;
  for ind in 1..7 loop
    tres_digitos := substr( valor_conv , (((ind-1)*3)+1) , 3 );
    texto_string := '' ;
    -- Extenso para Centena
    if substr(tres_digitos,1,1) = '2' then
      texto_string := texto_string || 'Duzentos ' ;
    elsif substr(tres_digitos,1,1) = '3' then
      texto_string := texto_string || 'Trezentos ' ;
    elsif substr(tres_digitos,1,1) = '4' then
      texto_string := texto_string || 'Quatrocentos ' ;
    elsif substr(tres_digitos,1,1) = '5' then
      texto_string := texto_string || 'Quinhentos ' ;
    elsif substr(tres_digitos,1,1) = '6' then
      texto_string := texto_string || 'Seiscentos ' ;
    elsif substr(tres_digitos,1,1) = '7' then
      texto_string := texto_string || 'Setecentos ' ;
    elsif substr(tres_digitos,1,1) = '8' then
      texto_string := texto_string || 'Oitocentos ' ;
    elsif substr(tres_digitos,1,1) = '9' then
      texto_string := texto_string || 'Novecentos ' ;
    end if;
    if substr(tres_digitos,1,1) = '1' then
      if substr(tres_digitos,2,2) = '00' then
        texto_string := texto_string || 'Cem ' ;
      else
        texto_string := texto_string || 'Cento ' ;
      end if;
    end if;
    -- Extenso para Dezena
    if substr(tres_digitos,2,1) <> '0' and texto_string is not null then
      texto_string := texto_string || 'e ';
    end if;
    if substr(tres_digitos,2,1) = '2' then
      texto_string := texto_string ||'Vinte ';
    elsif substr(tres_digitos,2,1) = '3' then
      texto_string := texto_string ||'Trinta ';
    elsif substr(tres_digitos,2,1) = '4' then
      texto_string := texto_string ||'Quarenta ';
    elsif substr(tres_digitos,2,1) = '5' then
      texto_string := texto_string ||'Cinquenta ';
    elsif substr(tres_digitos,2,1) = '6' then
      texto_string := texto_string ||'Sessenta ';
    elsif substr(tres_digitos,2,1) = '7' then
      texto_string := texto_string ||'Setenta ';
    elsif substr(tres_digitos,2,1) = '8' then
      texto_string := texto_string ||'Oitenta ';
    elsif substr(tres_digitos,2,1) = '9' then
      texto_string := texto_string ||'Noventa ';
    end if;
    if substr(tres_digitos,2,1) = '1' then
      if substr(tres_digitos,3,1) <> '0' then
        if substr(tres_digitos,3,1) = '1' then
          texto_string := texto_string ||'Onze ';
        elsif substr(tres_digitos,3,1) = '2' then
          texto_string := texto_string ||'Doze ';
        elsif substr(tres_digitos,3,1) = '3' then
          texto_string := texto_string ||'Treze ';
        elsif substr(tres_digitos,3,1) = '4' then
          texto_string := texto_string ||'Catorze ';
        elsif substr(tres_digitos,3,1) = '5' then
          texto_string := texto_string ||'Quinze ';
        elsif substr(tres_digitos,3,1) = '6' then
          texto_string := texto_string ||'Dezesseis ';
        elsif substr(tres_digitos,3,1) = '7' then
          texto_string := texto_string ||'Dezessete ';
        elsif substr(tres_digitos,3,1) = '8' then
          texto_string := texto_string ||'Dezoito ';
        elsif substr(tres_digitos,3,1) = '9' then
          texto_string := texto_string ||'Dezenove ';
        end if;
      else
        texto_string := texto_string ||'Dez ' ;
      end if;
    else
    -- Extenso para Unidade
      if substr(tres_digitos,3,1) <> '0' and texto_string is not null then
        texto_string := texto_string || 'e ';
      end if;
      if substr(tres_digitos,3,1) = '1' then
        texto_string := texto_string ||'Um ';
      elsif substr(tres_digitos,3,1) = '2' then
        texto_string := texto_string ||'Dois ';
      elsif substr(tres_digitos,3,1) = '3' then
        texto_string := texto_string ||'Tres ';
      elsif substr(tres_digitos,3,1) = '4' then
        texto_string := texto_string ||'Quatro ';
      elsif substr(tres_digitos,3,1) = '5' then
        texto_string := texto_string ||'Cinco ';
      elsif substr(tres_digitos,3,1) = '6' then
        texto_string := texto_string ||'Seis ';
      elsif substr(tres_digitos,3,1) = '7' then
        texto_string := texto_string ||'Sete ';
      elsif substr(tres_digitos,3,1) = '8' then
        texto_string := texto_string ||'Oito ';
      elsif substr(tres_digitos,3,1) = '9' then
        texto_string := texto_string ||'Nove ';
      end if;
    end if;
    if to_number( tres_digitos ) > 0 then
      if to_number( tres_digitos ) = 1 then
        if ind = 1 then
          texto_string := texto_string || 'Quatrilhão ' ;
        elsif ind = 2 then
          texto_string := texto_string || 'Trilhão ' ;
        elsif ind = 3 then
          texto_string := texto_string || 'Bilhão ' ;
        elsif ind = 4 then
          texto_string := texto_string || 'Milhão ' ;
        elsif ind = 5 then
          texto_string := texto_string || 'Mil ' ;
        end if;
      else
        if ind = 1 then
          texto_string := texto_string || 'Quatrilhões ' ;
        elsif ind = 2 then
          texto_string := texto_string || 'Trilhões ' ;
        elsif ind = 3 then
          texto_string := texto_string || 'Bilhões ' ;
        elsif ind = 4 then
          texto_string := texto_string || 'Milhões ' ;
        elsif ind = 5 then
          texto_string := texto_string || 'Mil ' ;
        end if;
      end if;
    end if;
    valor_string := valor_string || texto_string;
    -- Escrita da Moeda Corrente
    if ind = 5 then
      if to_number( substr( valor_conv , 16 , 3 )) > 0 and valor_string is
          not null then
        valor_string := rtrim(valor_string) || ', ';
      end if;
    else
      if ind < 5 and valor_string is not null then
        valor_string := rtrim(valor_string) || ', ';
      end if;
    end if;
    if ind = 6 then
      if to_number( substr( valor_conv , 1 , 18 ) ) > 1 then
        valor_string := valor_string || 'Reais ';
      elsif to_number( substr( valor_conv , 1 , 18 ) ) = 1 then
        valor_string := valor_string || 'Real ';
      end if;
     
      if to_number( substr( valor_conv , 20 , 2 ) ) > 0 and
           length(valor_string) > 0  then
        valor_string := valor_string || 'e ';
      end if;
    end if;
    -- Escrita para Centavos
    if ind = 7 then
      if to_number( substr( valor_conv , 20 , 2 ) ) > 1 then
        valor_string := valor_string  || 'Centavos ';
      elsif to_number( substr( valor_conv , 20 , 2 ) ) = 1 then
        valor_string := valor_string  || 'Centavo ';
      end if;
    end if;
  end loop;
  return( rtrim(valor_string) );
exception
  when others then
    return( '*** VALOR INVALIDO ***' );
end;


Ao testar:

Código: Selecionar todos
SQL> select extenso_monetario(1) ext from dual;

EXT
----------------------------------------------------------------------------------------------------
Um Real

SQL> select extenso_monetario(1.50) ext from dual;

EXT
----------------------------------------------------------------------------------------------------
Um Real e Cinquenta Centavos

SQL> select extenso_monetario(0.85) ext from dual;

EXT
----------------------------------------------------------------------------------------------------
Oitenta e Cinco Centavos

SQL> select extenso_monetario(785412698.58) ext from dual;

EXT
----------------------------------------------------------------------------------------------------
Setecentos e Oitenta e Cinco Milhões, Quatrocentos e Doze Mil, Seiscentos e Noventa e Oito Reais e Cinquenta e Oito Centavos


:-o

Abraços!!
Toad
Localização: Seattle, WA

Matheus H. Gonçalves
www.toad.com.br
www.twitter.com/toadgeek

Mensagemem Ter, 24 Out 2006 11:08 am

eae toad, no meu caso aqui estou fazendo um relatório fiscal, e estou usando um esquema no reports que é o &<totalpages>, ele me retorna o numero total de paginas, tenho tmb uma procedure chamada P_EXTENSO, que é muito parecida com essa acima, porem não estou conseguindo associar as duas coisas...
passageiromr
Localização: Santa Cruz do Rio Pardo

Mensagemem Ter, 24 Out 2006 11:09 am

eae toad, no meu caso aqui estou fazendo um relatório fiscal, e estou usando um esquema no reports que é o &<totalpages>, ele me retorna o numero total de paginas, tenho tmb uma procedure chamada P_EXTENSO, que é muito parecida com essa acima, porem não estou conseguindo associar as duas coisas...
passageiromr
Localização: Santa Cruz do Rio Pardo

Mensagemem Ter, 24 Out 2006 11:38 am

Se ele retorna o número total de páginas, você pode aplicar a função, passando esse número total de páginas como parâmetro da função.

Código: Selecionar todos
select extenso(var_total_pages) from dual;
Toad
Localização: Seattle, WA

Matheus H. Gonçalves
www.toad.com.br
www.twitter.com/toadgeek


  • Veja também
    Respostas
    ExibiÇões
    Última mensagem


    Voltar para PL/SQL

    Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 2 visitantes