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
Responder
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

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

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.

Selecionar tudo

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...
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

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

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

Selecionar tudo

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:

Selecionar tudo

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> 
Avatar do usuário
Toad
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 253
Registrado em: Sex, 18 Nov 2005 2:14 pm
Localização: Seattle, WA
Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c

Dr.

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

Selecionar tudo

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:

Selecionar tudo

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!!
Avatar do usuário
passageiromr
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Ter, 24 Out 2006 10:15 am
Localização: Santa Cruz do Rio Pardo
Contato:

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...
Avatar do usuário
passageiromr
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Ter, 24 Out 2006 10:15 am
Localização: Santa Cruz do Rio Pardo
Contato:

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...
Avatar do usuário
Toad
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 253
Registrado em: Sex, 18 Nov 2005 2:14 pm
Localização: Seattle, WA
Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c

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.

Selecionar tudo

select extenso(var_total_pages) from dual;
Responder
  • Informação
  • Quem está online

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