Arquivo da categoria: sql

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.

Guida de referência de SQL Básico

Fala pessoAll,

Com a contribuição do nosso amigo e leitor Robson Cristovão, está aí um guia básico de SQL que pode ser bastante útil para quem está começando no mundo SQL e tem algumas dúvidas quanto ao uso e sitaxe de alguns comandos SQL! Fica a dica!

AND | OR:
SELECT nome_coluna(s)
FROM nome_tabela
WHERE condiçao
AND | OR condiçao

ALTER TABLE (add coluna):
ALTER TABLE nome_tabela
ADD nome_coluna datatype

ALTER TABLE (drop column):
ALTER TABLE nome_tabela
DROP COLUMN nome_coluna

AS (alias for column):
SELECT nome_coluna AS coluna_apelido
FROM nome_tabela

AS (alias for table):
SELECT nome_coluna
FROM nome_tabela AS tabela_apelido

BETWEEN:
SELECT nome_coluna(s)
FROM nome_tabela
WHERE nome_coluna
BETWEEN valor1 AND valor2

CREATE (database):
CREATE DATABASE nome_base_de_dados

CREATE (index):
CREATE INDEX nome_indice
ON nome_tabela (nome_coluna)

CREATE (table):
CREATE TABLE nome_tabela(
nome_coluna1 tipo_dado,
nome_coluna2 tipo_dado,...)

CREATE (unique index):
CREATE UNIQUE INDEX nome_indice
ON nome_tabela (nome_coluna)

CREATE (view):
CREATE VIEW nome_da_view AS
SELECT nome_coluna(s)
FROM nome_tabela
WHERE condiçao

DELETE:
DELETE FROM nome_tabela
OU
DELETE FROM nome_tabela
WHERE condiçao

DROP (database):
DROP DATABASE nome_base_de_dados

DROP (index):
DROP INDEX nome_tabela.nome_indice

DROP (table):
DROP TABLE nome_tabela

GROUP BY:
SELECT nome_coluna1,SUM(nome_coluna2)
FROM nome_tabela
GROUP BY nome_coluna1

HAVING:
SELECT nome_coluna1,SUM(nome_coluna2)
FROM nome_tabela
GROUP BY nome_coluna1
HAVING SUM(nome_coluna2) valor_da_condiçao

IN:
SELECT nome_coluna(s)
FROM nome_tabela
WHERE nome_coluna
IN (valor1,valor2,..)

INSERT:
INSERT INTO nome_tabela
VALUES (valor1, valor2,....)
OU
INSERT INTO nome_tabela
(nome_coluna1, nome_coluna2,...)
VALUES (valor1, valor2,....)

LIKE:
SELECT nome_coluna(s)
FROM nome_tabela
WHERE nome_coluna
LIKE padrao

ORDER BY:
SELECT nome_coluna(s)
FROM nome_tabela
ORDER BY nome_coluna [ASC | DESC

SELECT:
SELECT nome_coluna(s)
FROM nome_tabela

SELECT (all):
SELECT * FROM nome_tabela

SELECT (distinct):
SELECT DISTINCT nome_coluna(s)
FROM nome_tabela

SELECT (into - usado para criar cópias auxiliares das tabelas):
SELECT * INTO new_nome_tabela
FROM original_nome_tabela
OU
SELECT nome_coluna(s)
INTO new_nome_tabela
FROM original_nome_tabela

TRUNCATE:
TRUNCATE TABLE nome_tabela

UPDATE:
UPDATE nome_tabela
SET nome_coluna=novo_valor
[, nome_coluna=novo_valor]
WHERE nome_coluna = algum_valor

WHERE:
SELECT nome_coluna(s)
FROM nome_tabela
WHERE condiçao

Espero que gostem.

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

Dica: Como descobrir quem referencia uma coluna?

Fala PessoAll,

A dica de hoje é a respeito do seguinte…

Muitas vezes temos a necessidade de fazer algumas alterações nas nossas tabelas, nosso modelo, etc. E aí precisamos levantar quais tabelas recerenciam uma determinada tabela ou coluna, quais as filhas dessas colunas, quais as foreign key que fazem referência a elas e etc.

Aí, podemos usar o seguinte select:


select distinct c.table_name
from dba_constraints c,
dba_cons_columns cc
where c.constraint_type = 'R'
and cc.owner = c.owner
and cc.constraint_name = c.r_constraint_name
and cc.owner = &SCHEMA
and cc.table_name = &TABELA
and cc.column_name = &COLUNA

Claro que temos que mudar os parâmetros &SCHEMA, &TABELA e &COLUNA, para recuperar as tabelas que são filhas da tabela que você deseja.

Exemplo fica melhor não? Vamos lá:

Eu preciso descobrir quais as tabelas que fazem referência a alguma coluna da tabela SOURCE, para tal fazemos o seguinte select:


SQL> select DISTINCT C.TABLE_NAME
2 from dba_constraints c,
3 dba_cons_columns cc
4 where c.constraint_type = 'R'
5 and cc.owner = c.owner
6 and cc.constraint_name = c.r_constraint_name
7 and cc.owner = 'ORABUGIT'
8 and cc.table_name = 'SOURCES'
9 /
TABLE_NAME
------------------------------
PEOPLE_EQUIPS

Como podemos ver, obtemos como resposta a tabela PEOPLE_EQUIPS, portanto podemos ver que nesta tabela tem alguma coluna que referencia através de foreign key uma coluna da tabela SOURCE.

Espero que a dica seja útil!!

Abraços.

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

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

Dica de SQL – Primeiro sábado do mês seguinte

Fala PessoAll,

Recebi um email do amigo Vitor Ugo sobre uma solicitação que ele havia recebido para criação de um Job.

Até aí moleza, como podemos ver no post: Job no Oracle criar um Job é fácil! Só que este Job tem uma particularidade, ele deve rodar apenas no primeiro sábado de cada mês.

Com isso, fiz a dica para Vitor, dele colocar o job para executar todo dia, e antes de chamar a procedure do job fazer um teste e identificar se era o primeiro sábado, se sim, beleza roda a procedure, senão, não faz nada! Funcionaria, porém não é uma solução das mais bonitas, porque mesmo sem fazer nada, o job executaria todos os dias.

Foi então que o Vitor desenvolveu um select, que recupera o primeiro sábado do mês seguinte, e resolveu todos os problemas.

Segue o select desenvolvido por Vitor:


select LEAST(NEXT_DAY(ADD_MONTHS(trunc(sysdate,'MM')+(8/24),1)-1,7),
next_day(ADD_MONTHS(trunc(sysdate,'MM')+(8/24),1),7)) from dual;

Neste select o “7” indica que é um sábado, caso desejem outro dia da semana, basta que vocês alterem esse número para o dia desejado!

É isso, fica aí a dica. Espero que gostem

Abraço a todos.

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

Função DECODE no Oracle SQL

Fala PessoAll,

Hoje vamos falar de Construção de SQL.

As vezes precisamos fazer umas coisas mais avançadas num comando SQL e aí precisamos utilizar alguns recursos mais interessantes que o Oracle nos proporciona.

Quem nunca pensou: “Ai como seria bom se tivesse um IF no select”. Tem sim!

O primeiro recurso que podemos utilizar é o DECODE, essa função é bem interessante e quebra um bocado de galhos, vamos ver um exemplo pra “clarear” as idéias.

Suponha que você tem uma tabela que contém o sexo das pessoas, mas na tabela só armazena F ou M e você quer que seja mostrado “Masculino” e “Feminino” no retorno do seu select, como fazemos isso no select? Com DECODE!

Assim:


select nome,
dt_nascimento,
decode(sexo,
'M', 'Masculino',
'F', 'Feminino',
'Indefinido') sexo
from pessoas;

Como funciona isso… o DECODE testa o valor que você passa no primeiro parâmetro e vai comparando com o que você especifica e retorna o que você deseja. Complexo não? NÃO!! Vamos explicar o nosso exemplo:

No exemplo acima é passado o campo sexo, em seguida passamos o primeiro valor de teste e o que vai retornar caso encontre este valor, que neste caso é: Se encontrar 'M' retorne 'Masculino', sempre aos pares. Ou seja, valor encontrado e logo depois o valor que vai retornar. Como podemos ver, depois vem mais um par… 'F' e 'Feminino' o que nos diz que se encontrar um 'F', traga 'Feminino' na coluna.

Tá, mas e esse último valor que tem 'Indefinido'? Ele não tem par!! Vai dar erro? Não, esse é uma espécie de ELSE do DECODE… se ele não encontrar nenhuma das alternativas passadas para retornar um valor especificado, ele retorna esse último valor. No nosso exemplo, podemos ver que caso não encontre 'M' nem 'F' no campo, ele irá retornar o valor 'Indefinido' para a coluna… agora ficou claro!

O DECODE não tem um limite mínimo nem máximo de “pares de teste e retorno”, você pode ir especificando os valores e os retornos de acordo com sua necessidade.

Bom, esse é um recurso do Oracle que pode ser bem útil para pessoas que fazem SQL, que elaboram relatórios, que vivem fazendo query entre outros casos.

Como podemos verificar, para usar o DECODE nós temos que saber os valores que estão na coluna para que possamos informar qual o retorno caso determinado valor seja encontrado, mas… e se eu quiser utilizar uma faixa de valores por exemplo? Tipo… se coluna nota estiver entre 0 e 3 retorno 'Péssimo', entre 4 e 5 retorne 'Ruim', entre 6 e 8 retorne 'Bom' e acima de 8 retorne 'Ótimo'? Não dá pra fazer isso com DECODE né? Mas, tenha calma… no próximo post falaremos sobre uma outra função do Oracle que é uma espécie de DECODE avançado, que permite esse tipo de teste e muito mais.

Espero que gostem e que seja útil. Até a próxima.

Não exitem em comentar e/ou mandar e-mails.

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

Oracle Execute Immediate SQL Dinâmico

Fala pessoAll,

Vamos nós novamente.
A pedido do amigo Marcos Castro dessa vez estaremos falando sobre SQL Dinâmicos, um recurso muito interessante no PL/SQL que em diversas vezes não é utilizado por nossos excelentíssimos desenvolvedores, fazendo com que nossos códigos sejam bem maiores, bem mais complexos e bem mais chatos de dar manutenção. Mas… o lado B dessa história é: Se você complicar muito no uso de SQL Dinâmico, não tenha dúvida de que seu código vai ficar muito complexo e todo mundo que for dar manutenção vai te xingar um bocado! Rsrs.

Vamos lá, ao exemplo prático e simples, que é o que interessa.

Suponha que você tem uma função para ser feita, que deve retornar o nome de uma determinada pessoa… essa pesquisa pode ser pelo seu RG, CPF ou Habilitação. Como podemos fazer isso?

Exemplo 1 (sem SQL Dinâmico):

create or replace function pesquisa_pessoa(pcodigo number, pfiltro varchar2) return varchar2 is
v_nome_pessoa pessoas.nome%type;
begin
if(pfiltro = ‘RG’) then
select nome
into v_nome_pessoa
from pessoas
where rg = pcodigo;
elsif(pfiltro = ‘CPF’) then
select nome
into v_nome_pessoa
from pessoas
where cpf = pcodigo;
elsif(pfiltro = ‘CNH’) then
select nome
into v_nome_pessoa
from pessoas
where cnh = pcodigo;
end if;

return v_nome_pessoa;
end;

Notemos que o SQL é o mesmo sempre (select nome into v_nome_pessoa from pessoas where … = pcodigo ), o que muda é apenas o nome do campo que será utilizado para filtrar a pessoa, portanto, podemos utilizar o recurso de SQL Dinâmico para otimizar este código, e como ele ficaria? Assim:

create or replace function pesquisa_pessoa(pcodigo number, pfiltro varchar2) return varchar2 is
v_nome_pessoa pessoas.nome%type;
v_where varchar2(50);
begin
if(pfiltro = ‘RG’) then
v_where := ‘rg’;
elsif(pfiltro = ‘CPF’) then
v_where := ‘cpf’;
elsif(pfiltro = ‘CNH’) then
v_where := ‘cnh’;
end if;

dbms_output.put_line(‘select nome into v_nome_pessoa from pessoas where ‘||v_where||’ = ‘||pcodigo||’;’);

execute immediate ‘select nome from pessoas where ‘||v_where||’ = ‘||pcodigo
into v_nome_pessoa;

return v_nome_pessoa;
end;

Bem mais simples, e não precisamos ficar repetindo o mesmo comando várias vezes.

Bom, isso é só um exemplo bem simples, mas… o Execute Immediate pode ser usado de diversas outras maneiras.

Achei um site bem interessante, que mostra as diversas usabilidades deste recurso com exemplos que podem ser utilizados para um melhor entendimento. O site é o DBA Support.

É isso aí, espero que este recurso seja útil e bem utilizado nas suas aplicações.

Atc.

Gerson Júnior

(gerson.vasconcelos@gmail.com)