Arquivo da categoria: function

Alternativa InitCap. Upper e Lower no lugar certo.

Fala PessoALL,

Hoje falaremos de manipulação/formatação de strings, com o uso da boa e velha função InitCap do Oracle.
Acho que muitos de nós já nos deparamos com este tipo de problema, temos no nosso banco, uma determinada descrição gravada da forma que o usuário achar mais bonito! Ou seja, sem ter um padrão para gravação. Para gravar a frase: “Este blog é uma beleza”, por exemplo, podemos ter de várias formas:

– Este blog é uma beleza
– ESTE BLOG É UMA BELEZA
– EsTe BlOg É uMa BeLeZa (vai que o usuário é internetês)

Entre muitas outras formas. Porém na hora de fazermos um relatório, gostaríamos muitas vezes que nosso relatório mantenha um padrão de exibição da descrição, fica no mínimo estranho que tenhamos uma frase maíuscula, outra minúscula, outra mesclada, etc… para isso o Oracle nos dá uma função chamada InitCap.

Esta função nos dá a possibilidade de padronizar a nossa descrição, ela coloca maiúscula todas as primeiras letras das palavras da frase, por exemplo:

– Este Blog É Uma Beleza

Só que este ainda não é o padrão que utilizamos para escrever, apenas as primeiras letras da primeira palavra da frase é que são maiúsculas. Todas as demais são minúsculas, ficando a frase assim:

-Este blog é uma beleza

Bem mais bonito não??

Pensando nesse problema, vamos deixar de blábláblá e vamos a prática!

Eu desenvolvi uma função, a pedido do meu amigo Marcos Castro, que faz exatamente isso que queremos, ela só coloca maíuscula a primeira letra da primeira palavra de uma nova frase, ou seja, o que vem depois do ponto, como costumamos fazer no nosso dia-a-dia, como mostrado no exemplo acima.

Segue a função:


create or replace function initcapmc(p_str varchar2) return varchar2 is
v_carac_anterior varchar2(1);
v_carac_atual varchar2(1);
v_retorno varchar2(32767);
begin
--Atribui o primeiro caractere como maiúsculo.
v_retorno := upper(substr(p_str,1,1));

--Varre a string a partir da segunda posição
for i in 2..length(p_str) loop
--Recupera o caractere que está sendo analisado
v_carac_atual := substr(p_str,i,1);

--Se o caractere analisado anteriormente foi um ponto, vai colocar maiúsculo
if(v_carac_anterior = '.') then
v_retorno := v_retorno || upper(v_carac_atual);
else
v_retorno := v_retorno || lower(v_carac_atual);
end if;

--Atribui o caractere já processado como sendo o anterior, para a proxima execucao. Ignora espaco.
if(trim(v_carac_atual) is not null) then
v_carac_anterior := v_carac_atual;
end if;
end loop;

return v_retorno;

end;

Espero que gostem… em caso de bugs, favor informar.

Atc.
Gerson Júnior
(gerson.vasconcelos@gmail.com)

Função de grupo para multiplicar, SUM -> MULT

Fala pessoal,

Recebi um email de um leitor solicitando uma solução para que fosse desenvolvida uma função semelhante ao SUM, já nativo do banco de dados Oracle, só que fizesse multiplicação e não soma, como o SUM faz atualmente!

Por exemplo:

Tabela: FATORIAL
Campo: VALOR

Valor
5
6
3
2
3

Portanto, se usarmos o SUM, teriamos um resultado assim: 5 + 6 + 3 + 2 + 3 = 19
O pretendido é: 5 * 6 * 3 * 2 * 3 = 540

A sugestão que dei foi: Criar uma função própria que faça a multiplicação dos valores. A implementação/testes ficou assim:


SQL> --Cria tabela
SQL> create table fatorial(campo1 number, valor number);
Tabela criada.
SQL> --Insere valores
SQL> insert into fatorial values (1,2);
1 linha criada.
SQL> insert into fatorial values (1,3);
1 linha criada.
SQL> insert into fatorial values (2,4);
1 linha criada.
SQL> insert into fatorial values (2,4);
1 linha criada.
SQL>

Em seguida criamos a seguinte function:


SQL> create or replace function mult_vals(p_filtro number) return number is
2 v_retorno number;
3 begin
4 v_retorno := 0;
5 for i in (select valor from fatorial where campo1 = p_filtro)
6 loop
7 if (v_retorno = 0) then
8 v_retorno := 1;
9 end if;
10 v_retorno := v_retorno*i.valor;
11 end loop;
12 return v_retorno;
13 end;
14 /
FunþÒo criada.
SQL>

E depois é só testar:


SQL> select campo1, mult_vals(campo1)
2 from fatorial
3 group by campo1;
CAMPO1 MULT_VALS(CAMPO1)
---------- -----------------
1 6
2 16
SQL>

Funcionou como uma luva não?

É isso, o que não tem nativo a gente faz!
Neste caso fiz algo bem específico, só pra atender a necessidade que nosso leitor precisava, mas podemos pensar em algo mais genérico, se necessário! Usando SQL Dinâmico, passando nome do campo a ser multiplicado e nome da tabela! Fica a sugestão!

Agradecendo ao nosso leitor Rodrigo Vieira pela solicitação!!

Grande abraço, espero que gostem.

Potência / Expoentes em SQL e PL/SQL – Oracle

Fala Pessoal,

Hoje vai mais uma dica de SQL e PL/SQL.

Até o dia de hoje, eu nunca tinha necessitado usar expoente no SQL / PL/SQL, nunca tinha pego nenhum problema em desenvolvimento que precisasse ser usado potência, expoente e tal.

Porém, hoje uma amiga desenvolvedora, Leilah, precisou dessa funcionalidade e aí discutimos um pouco sobre o assunto. Descobri portanto, que no Oracle, não precisamos fazer muita conta e nem usar sintaxes esquisitas para usar potência e elevar um número a uma determinada potência, basta usarmos a função POWER, isso mesmo, funciona assim:

Exemplo SQL:

SQL> select power(2,3) from dual;
POWER(2,3)
----------
8

Neste exemplo, temos 2 elevado a 3, que nos dá 8 como resultado…

Exemplo PL/SQL:

SQL> declare
2 v_num number;
3 begin
4 v_num := power(2,3);
5 dbms_output.put_line('O numero 2 elevado a 3 é: '||to_char(v_num));
6 end;
7 /
O numero 2 elevado a 3 é: 8
Procedimento PL/SQL concluÝdo com sucesso.

Pronto pessoal, fica aí a dica de utilização de potência em PL/SQL.

Espero que gostem.

Grande abraço.

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

Validando Digito Verificador Inscrição Estadual Bahia (BA)

Fala PessoAll,

Bom, como toda e boa pessoa normal, de vez em quando bate a saudade das épocas de desenvolvimento, de quebrar cabeça para fazer alguns códigos “ninja” pra resolver alguns problemas do nosso Dia a Dia (Oracle, rsrs).

Otem me deparei com a demanda de um amigo, precisando fazer uma validação do dígito da Inscrição estadual da Bahia, em PL/SQL. Vamos lá!

Primeiro passo: Pesquisar como se faz a validação do dígito verificador da inscrição estadual da BAHIA!! BAHIA!! Ninguém melhor que a Sefaz/BA pra me dizer isso. Então, fui no site da SEFAZ/BA e achei como fazer a validação, depois foi só cair no PL/SQL de cabeça e colocar pra funcionar. A página que diz como deve ser feita a validação é: http://www.sefaz.ba.gov.br/contribuinte/informacoes_fiscais/doc_fiscal/calculodv.htm.

Segue abaixo a function utilizada para fazer esta validação. Essa function retorna ‘S’ caso esteja OK e ‘N’ caso não seja validado o dígito verificador.


create or replace function valida_dig_inscest_BA(pInscEstadual varchar2) return varchar2 is
v_IE varchar2(10);

idig1 number;
idig2 number;

iRes1 number;
iRes2 number;

cBase1 number;
cBase2 number;
begin
v_IE := rtrim(replace(replace(replace(pInscEstadual, '.', ''), '-', ''), '/', ''));

if length(v_IE) <> 8 then
return('N');
end if;

iRes1 := 0;
iRes2 := 0;

cBase1 := substr(v_IE, 1, 6);
iDig1 := substr(v_IE, 7, 1);
iDig2 := substr(v_IE, 8, 1);

--Se o primeiro dígito for um dos testados, modulo 10, senao, modulo 11
if(substr(cBase1, 1, 1) in (0, 1, 2, 3, 4, 5, 8)) then
--Faz um loop de 7 até 2...
for i in reverse 2 .. 7 loop
--Verifica se o numero encontrado é válido.
if instr('0123456789', SubStr(cBase1, (7-i)+1, 1)) > 0 Then
--Sendo válido, já soma com a multiplicação pelo indice.
ires2 := ires2 + (SubStr(cBase1, (7-i)+1, 1) * i);
else
return('N');
end if;
end loop;

--Recupera o resto do calculo realizado por 10
ires2 := mod(ires2, 10);

--Se for 0, o digito é zero.
if(ires2 = 0) then
ires2 := 0;
--Se não for zero, subtrai o valor de 10
else
ires2 := 10 - ires2;
end if;

--O numero para o calculo do primeiro digito, é os 6 primeiros + o digito 2
cBase2 := cBase1||ires2;

--Faz um loop de 8 até 2...
for i in reverse 2 .. 8 loop
--Verifica se o numero encontrado é válido.
if instr('0123456789', SubStr(cBase2, (8-i)+1, 1)) > 0 Then
--Sendo válido, já soma com a multiplicação pelo indice.
ires1 := ires1 + (SubStr(cBase2, (8-i)+1, 1) * i);
else
return('N');
end if;
end loop;

--Recupera o resto do calculo realizado por 10
ires1 := mod(ires1, 10);

--Se for 0, o digito é zero.
if(ires1 = 0) then
ires1 := 0;
--Se não for zero, subtrai o valor de 10
else
ires1 := 10 - ires1;
end if;

--Se resultado 1 e 2 iguais a digitos 1 e 2, é válido
if(ires1 = idig1 and ires2 = idig2) then
return('S');
else
return('N');
end if;
--Se começa com 6, 7 ou 9
else
--Faz um loop de 7 até 2...
for i in reverse 2 .. 7 loop
--Verifica se o numero encontrado é válido.
if instr('0123456789', SubStr(cBase1, (7-i)+1, 1)) > 0 Then
--Sendo válido, já soma com a multiplicação pelo indice.
ires2 := ires2 + (SubStr(cBase1, (7-i)+1, 1) * i);
else
return('N');
end if;
end loop;

--Recupera o resto do calculo realizado por 11
ires2 := mod(ires2, 11);

--Se for 0, o digito é zero.
if(ires2 = 0) then
ires2 := 0;
--Se não for zero, subtrai o valor de 11
else
ires2 := 11 - ires2;
end if;

--O numero para o calculo do primeiro digito, é os 6 primeiros + o digito 2
cBase2 := cBase1||ires2;

--Faz um loop de 8 até 2...
for i in reverse 2 .. 8 loop
--Verifica se o numero encontrado é válido.
if instr('0123456789', SubStr(cBase2, (8-i)+1, 1)) > 0 Then
--Sendo válido, já soma com a multiplicação pelo indice.
ires1 := ires1 + (SubStr(cBase2, (8-i)+1, 1) * i);
else
return('N');
end if;
end loop;

--Recupera o resto do calculo realizado por 10
ires1 := mod(ires1, 11);

--Se for 0, o digito é zero.
if(ires1 = 0) then
ires1 := 0;
--Se não for zero, subtrai o valor de 10
else
ires1 := 11 - ires1;
end if;

if(ires1 = idig1 and ires2 = idig2) then
return('S');
else
return('N');
end if;
end if;
end;

É isso aí gente, espero que seja útil.

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com

Usando CASE no Oracle SQL.

Fala PessoAll,

Bom, conforme prometido no Post anterior, estou aqui para dar uma apimentada na utilização da função DECODE usando SQL Oracle.

A funcionalidade que iremos falar hoje é a CASE. Esta funcionalidade é muito boa e dá uma dinâmica muito interessante a comandos SQL, em muitas vezes nos poupando de ter que fazer uma Stored Prodecure ou uma Function para fazer alguma coisa que um simples SQL pode resolver.

Para não fugir dos costumes… vamos ao exemplo.

Suponha que você tenha 3 classificações diferentes para seus vendedores, que funcionam da seguinte forma: Se o cara vendeu entre R$0.00 e R$1,000.00 ele é classificado como “Ruim”, se foi entre R$1,001.00 e R$4,000.00 ele é classificado como “Bom”, se foi entre R$4,001.00 e R$8,000.00 ele é classificado como “Ótimo” e se for acima de R$8,001.00 ele é considerado como “Fenomenal”, e você precisa exibir isso no relatório para sua gerência.

Como fazer isso?

Aí você começa a pensar…
DECODE? Não dá… tenho faixa de valores, e não valores específicos!

Cria uma View? Não… uma view é um mero Select, não vai resolver!

Ah…. claro! Cria uma função!!! Na função eu passo o valor que o cara vendeu e ela me retorna qual a classificação do cara! Perfeito!
É…. funcionar vai funcionar, mas você tem que criar um objeto no banco, tem que criar um Script, tem que se preocupar com Grant’s e todos os demais aspectos para que criemos um novo objeto!

Não seria mais simples que no próprio Select a gente resolvesse esse problema? SIM!!! Claro!! Porque não. Para isso, vamos usar a funcionalidade CASE. Como faríamos isso, para este caso?

Agora sim, cenário montado, vamos ao exemplo (de verdade):


select v.nome_vendedor,
ve.mes,
ve.vlr_meta,
ve.vlr_venda,
case
when ve.vlr_venda between 0 and 1000 then
'Ruim'
when ve.vlr_venda between 1001 and 4000 then
'Bom'
when ve.vlr_venda between 4001 and 8000 then
'Ótimo'
when ve.vlr_venda >= 8001 then
'Fenomenal'
end classificacao_vendedor
from vendedores v,
vendas ve
where ve.cod_vendedor = v.cod_vendedor;
and ve.mes = '07/2009';

Que beleza não? Resolvido nosso provlema! Temos agora em nosso SQL a coluna classificacao_vendedor que nos dá a informação que precisamos, sem problemas com criação de função nem nada do tipo!

Bom não? Simples de usar, rápido e tudo quanto é de vantagem!

É isso aí, creio que a partir desse exemplo dá pra “voar” bem alto! Agora é só adaptar para sua necessidade e tá tudo certo!!

Espero que gostem e comentem!

Atc.
Gerson Júnior
gerson.vasconcelos@gmail.com