Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

Oracle Tuning – Exportando Estatísticas de Tabelas

Fala PessoAll,

Depois de muito tempo sem postar, estou eu aqui de novo para falar de mais um recurso usado no nosso Diaadia.

Desta vez o problema foi o seguinte:

Temos uma base de produção 9i que está em plena fase de migração para 11g, claro que para que esta migração aconteça, temos que ter a homologação de vários sistemas em 11g, que atualmente rodam na nossa base de produção 9i. Em uma das homologações deste sistema, o analista nos acionou informando que um processo que rodava na base 9i em 10 minutos, já estava a mais de 1 hora rodando na base 11g, sem sucesso.

Vamos as análises…

Passo 1: Identificar que comando estava causando nosso problema, para isso solicitei ao analista rodar a rotina dele habilitando um trace, para tentarmos identificar. Foi solicitado adicionar os seguintes comandos na execução:

begin
--Habilita geracao do trace.
execute immediate('alter session set tracefile_identifier=''TRACE_PROC_LENTA''');
sys.dbms_support.start_trace(true, true);
-- Call the procedure
PROCEDURE_DO_ANALISTA_LENTA;
--Finaliza geracao do trace.
sys.DBMS_SUPPORT.STOP_TRACE;
end;
/

Após concluído o processo, temos que procurar na nossa pasta UDUMP o trace que foi gerado com o identificador “_TRACE_PROC_LENTA”.

Analisando o trace…

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 791 0.02 1.25 0 3 0 0
Execute 72124 9.77 127.63 365 3759 75246 7469
Fetch 81349 109.26 2466.37 229643 14999926 0 75146
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 154264 119.05 2595.27 230008 15003688 75246 82615

Identificamos que o processo rodou em 2595.27 segundos, total!

E temos um comando único, que rodou em 2289.73 segundos. Ficou claro que este é o culpado não??


select COL1, COL2, COL3 from MINHA_TABELA

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 5430 1.11 3.54 0 0 0 0
Fetch 5430 106.61 2286.19 222786 14703253 0 3431
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 10861 107.72 2289.73 222786 14703253 0 3431

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 214 (OWNER) (recursive depth: 1)

Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID MINHA_TABELA (cr=7 pr=0 pw=0 time=68 us cost=5 size=33 card=1)
13 INDEX RANGE SCAN MINHA_TABELA_IDX2 (cr=4 pr=0 pw=0 time=40 us cost=4 size=0 card=1)(object id 32870)

Como podemos ver, este select está sendo executado utilizando um índice, o MINHA_TABELA_IDX2. Ótimo, agora vamos comparar este plano de execução, com o plano de execução que temos em produção. Eis o plano de produção:


Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID MINHA_TABELA (cr=7 pr=0 pw=0 time=68 us cost=5 size=33 card=1)
13 INDEX RANGE SCAN MINHA_TABELA_PK (cr=4 pr=0 pw=0 time=40 us cost=4 size=0 card=1)

Opa…. qual a diferença? Nesta base a minha query acessa os dados pela PK, e não pelo índice! Matamos a parada!!!

Como resolver?

A base onde a homologação estava sendo feita era uma base 11g criada com uma cópia antiga de produção, que não vinha sendo coletada estatística, que estava sendo constantemente alterada pelos testes e que não estava 100%. Para coletar estatísticas novamente desta tabela, seria mais complicado e demorado, pois a tabela tem 667.000.000 de linhas, claro, o teste tem que ser agora!!!!

Lembramos então que tinhamos uma cópia fresquinha da base de produção, que tinha sido recém migrada para 11g, ou seja, estava em 11g, mas tinha as estatísticas certinhas de produção, onde a query estava rápida.

A solução encontrada foi: Exportar as estatísticas desta tabela.

Então, vamos lá…

Passo 1: Criar uma tabela de estatísticas na base origem, para receber as estatísticas atuais da tabela:


SQL> exec SYS.DBMS_STATS.CREATE_STAT_TABLE(ownname => 'DBAGABOS', stattab => 'TLISTENER_STATS');
Procedimento PL/SQL concluÝdo com sucesso.
SQL>

Passo 2: Exportar as estatísticas atuais da tabela na base de origem, para a tabela de esatísticas que você criou:


SQL> exec DBMS_STATS.EXPORT_TABLE_STATS(ownname => 'DBAGABOS', tabname => 'TLISTENER', stattab => 'TLISTENER_STATS', cascade => true);
Procedimento PL/SQL concluÝdo com sucesso.
SQL>

Passo 3: Exportar esta tabela gerada…


C:\Users\GersonJr>exp dbagabos@orcl tables=TLISTENER_STATS file=dump_stats.dmp
Export: Release 10.2.0.3.0 - Production on Seg Ago 1 19:23:58 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Senha:
Conectado a: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
ExportaþÒo executada no conjunto de caracteres de WE8MSWIN1252 e no conjunto de caracteres de AL16UTF16 NCHAR
Sobre exportar tabelas especificadas ... via Caminho Convencional ...
. . exportando tabela TLISTENER_STATS 113 linhas exportadas
ExportaþÒo encerrada com sucesso, sem advertÛncias.
C:\Users\GersonJr>

Passo 4: Importar a tabela de estatísticas que você exportou, no banco de destino…


C:\Users\GersonJr>imp dbagabos@orcl_destino tables=TLISTENER_STATS file=dump_stats.dmp
Import: Release 10.2.0.3.0 - Production on Seg Ago 1 19:24:58 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Senha:
Conectado a: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
Arquivo de exportaþÒo criado por EXPORT:V10.02.01 via caminho convencional
AdvertÛncia: os objetos foram exportados por DBAGABOS; nÒo por vocÛ
importaþÒo realizada nos conjuntos de caracteres WE8MSWIN1252 e NCHAR AL16UTF16
. importando objetos de DBAGABOS para DBAGABOS
. importando objetos de DBAGABOS para DBAGABOS
. . importando table "TLISTENER_STATS" 113 linhas importadas
ImportaþÒo encerrada com sucesso, sem advertÛncias.
C:\Users\GersonJr>

Passo 5: Importar as estatísticas para a tabela, lendo da tabela de estatísticas que você importou.

exec DBMS_STATS.IMPORT_TABLE_STATS(ownname => 'DBAGABOS', tabname => ‘TLISTENER’, stattab => ‘TLISTENER_STATS’, cascade => true, no_invalidate => true);

E agora é só você testar seu plano de execução e verificar se na base nova a query está se comportando da mesma forma que na base antiga.

Algumas considerações:
1 – O problema ocorreu na base 11g, porém para criar o post refiz os comandos na base instalada no meu PC, que é 10.2.0.3, como podem ver nos comandos acima.

2 – Estes passos não querem dizer que há uma garantia 100% da sua query ficar igual a sua base de origem, lembre-se que em performance existem inúmeros outros pontos que são verificados para o banco montar um plano de execução.

3 – A idéia deste post é mostrar este recurso de export/import de estatísticas, que é simples e rápido de fazer, e pode ajudar-nos em vários casos.

Qualquer coisa, estou à disposição para dúvidas e/ou sugestões!

Grande abraço.

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

Dica EXPDP – COMPRESSION

Fala PessoAll,

Estive fazendo um EXPDP de uma base de aproximadamente 360Gb.


nohup expdp userid=myusr/mypwd directory=DIR_EXPORT_SCHEMA dumpfile=exp_MS_MSI_18032011.dmp logfile=exp_MS_MSI_18032011.log schemas=MS,MSI status=300

Iniciei o export, e o directory DIR_EXPORT_SCHEMA estava em uma partição que tinha 112Gb livre, imaginei que o export ocorreria sem problemas, porém… de repente… erro no log, ao verificar, disco estava em 100% de uso. Ou seja, ele gerou um arquivo de 112Gb!

Então, lembrei que no bom e velho EXP tinha um parâmetro COMPRESS e decidi ver como era agora no novo EXPDP. Verificando o Help (expdp help=y), encontrei o parâmetro COMPRESSION e passei a utilizá-lo no meu comando, ficando assim:


nohup expdp userid=myusr/mypwd directory=DIR_EXPORT_SCHEMA dumpfile=exp_MS_MSI_18032011.dmp logfile=exp_MS_MSI_18032011.log schemas=MS,MSI compression=ALL status=300

Depois da conclusão do processo, fui ver o tamanho do arquivo e tive um baita surpresa! O dump inteiro ficou com 31Gb! Ou seja, sem compressão, chegamos em 112Gb e estourou o disco, com a compressão ficou em 31Gb.

Fica a dica, caso alguém tenha alguma restrição de espaço, manda bala com o COMPRESSION do EXPDP que realmente funciona, e a compressão é BEM significativa!

Abraços.

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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)

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

Oracle – Sinônimos públicos (public synonyms). Quando devo usar?

Fala PessoALL,

Depois de muito tempo sem escrever, vamos nós de novo!

Tenho me deparado sempre com dúvidas de desenvolvedores quanto ao uso de sinônimos públicos. Devemos usar? Não devemos? Cria pra todos os objetos? Não cria? Vamos tentar de uma vez por todas desvendar esse mistério de public synonym no Oracle.

Bom, sinônimos, como bem sabemos são palavras que tem o mesmo significado… isso no português! No Oracle, sinônimo é um pouco diferente, porém sendo um pouco igual! Confuso não? Rs. Vamos simplificar!

No Oracle o sinônimo público (public synonym) é um objeto de banco, cujo dono é PUBLIC (ou seja, todo mundo) que “aponta” para um outro objeto de um determinado schema. Como se fosse uma espécie de link. Por exemplo:

Imagine que você tem uma tabela no schema DONOSIS chamada MINHATABELA. Caso algum usuário que não seja DONOSIS deseje executar um select nesta tabela, você faz o seguinte comando: select * from donosis.minhatabela, mas e se eu não quiser colocar o dono do objeto na frente? Seja para que meus usuários não saibam quem é o dono dos objetos (questões de segurança), seja para que eu simplifique a codificação? Aí eu uso o sinônimo público! Eu crio um sinônimo púbico chamado MINHATABELA que aponta para o objeto de banco: DONOSIS.MINHATABELA. O código para criação é:

create or replace public synonym MINHATABELA for DONOSIS.MINHATABELA;

Após a criação deste sinônimo público, qualquer usuário do banco que executar o select select * from MINHATABELA; conseguirá de forma transparente acessar a tabela MINHATABELA do schema DONOSIS sem nem saber que ela se encontra neste schema! Simples não?

Isso pode ser utilizado para qualquer objeto de banco, como: Views, Procedures, Functions, Packages, Tables, etc.

Claro que para que o acesso ao objeto seja concluído, o usuário que está acessando tem que possuir privilégio no objeto de destino. Ou seja, mesmo com sinônimo público, os privilégios que foram concedidos no objeto de destino continuam funcionando normalmente.

Vantagens?
Simplicidade de codificação (não precisa colocar o nome do dono do objeto na frente).
Transparência de propriedade (não se sabe quem é o dono do objeto).
Simples modificação de objetos (você pode mudar o dono dos objetos, sem impacto algum).

Quando não usar?
Quando o objeto só será utilizado pelo próprio dono. Por exemplo: Se nossa tabela MINHATABELA fosse utilizada apenas por objetos do schema DONOSIS, não tinhamos a menor necessidade de ter um sinônimo, o objeto sendo do próprio schema, não precisamos colocar o schema na frente!

Erros mais comuns:
ORA-01775 loop chain of synonyms – Este erro ocorre geralmente quando ocorre algum problema com o objeto destino que o sinônimo aponta, por exemplo: Se for uma procedure que está inválida; Se for uma tabela que não existe; algo do tipo!

É isso pessoal, espero que tenha ficado claro como funciona e para que serve os sinônimos públicos (public synonym). Por enquanto é só!

Qualquer coisa, basta entrar em contato.

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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.

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

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

Lomadee, uma nova espécie na web. A maior plataforma de afiliados da América Latina

Copiar tabela no Oracle – Backup de tabela

Fala PessoAll,

Uma coisa bastante útil e bastante simples que podemos precisar no nosso dia a dia é fazer uma cópia de uma determinada tabela do nosso banco de dados.

Possíveis casos:

1 – Um update nas colunas;
2 – Deleção de alguns registros;

Entre outros que envolvam os dados contidos nesta tabela.

Portanto, em casos como esses, queremos garantir que caso dê alguma “caca” tenhamos de onde recuperar as informações rapidamente, nada mais rápido que um select em uma tabela que encontra-se no mesmo banco, sem precisar voltar backup, sem precisar acionar DBA, sem nada.

Vamos ao exemplo:

Vamos supor que temos em nosso banco de dados uma tabela de módulos do nosso sistema, chamada TB_MODULOS, e precisaremos fazer umas alterações nesta tabela… Para garantir, vamos fazer uma cópia dela.

Primeiro vamos contar quantos registros temos na nossa tabela de origem, pra ter certeza que a cópia levou tudo, não adianta termos uma cópia inconsistente!

SQL> select count(*) from tb_modulos;
COUNT(*)
----------
264960

Beleza, nossa tabela tem 264.960 linhas! Portanto, nossa cópia tem que estar exatamente igual!!

Vamos agora fazer a cópia da tabela:

SQL> create table tb_modulos_22012010 as select * from tb_modulos;
Tabela criada.

Depois da tabela criada, vamos contar a nova tabela, pra garantir que tem a mesma quantidade de registros!!

SQL> select count(*) from tb_modulos_22012010;
COUNT(*)
----------
264960

Pronto, nossa cópia funcionou perfeitamente, todos os 264.960 registros que tinhamos em TB_MODULOS agora estão em TB_MODULOS_22012010, podemos agora proceder com as alterações na tabela de módulos sem maiores problemas no caso de ocorrer um erro! Garantia é o melhor remédio!!! Rsrs.

Portanto, vimos que temos como fazer uma cópia de forma rápida de uma tabela do nosso banco de dados. O comando padrão para isso é: create table "TABELA_NOVA" as select * from "TABELA_ANTIGA", lembrando que desta forma você faz uma cópia da tabela inteira, mas você pode muito bem selecionar apenas algumas colunas, fazer um filtro usando uma cláusula where e etc… a “moral da história” é que: será criada uma tabela nova com o resultado do select que você fizer!!

Mas… depois da alteração pronta e validada, lembrem-se de dropar a tabela de backup.

Espero que gostem e que seja útil!

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