Arquivo da categoria: dicas

Guob Tech Day 2017 – Um novo evento

Olá PessoALL,

Este ano o Guob Tech Day será excepcional, e estará de cara nova! Lugar novo, novas salas simultâneas, temas novos, palestrantes sensacionais!

Enfim… já valia a pena comparecer no evento, agora… muito mais!

Abaixo alguns detalhes:

E alguns links:

Agenda: https://guobtechday2017.eventize.com.br/index.php?pagina=3
Local: https://guobtechday2017.eventize.com.br/index.php?pagina=5
Valores: https://guobtechday2017.eventize.com.br/index.php?pagina=4
Inscrição: https://guobtechday2017.eventize.com.br/index.php?inscricao

 

É isso aí! Vamos lá!!

 

Abraços!

Oracle 11G IMPDP – TRANSFORM – Caso Compress

Olá PessoAll,

Não sei se todos conheciam isso, eu particularmente nunca tinha usado, resolvi compartilhar.

Eu precisava fazer um import de um owner que atualmente está em tablespace normal, e tem suas tabelas normais para que ele fosse importado em uma outra tablespace e já comprimido (COMPRESS).

Fiz o export normalmente, sem nenhum segredo. Na hora do import que seriam realizadas as mudanças.

No import, a primeira coisa é que eu precisava era colocar as tabelas e índices numa nova tablespace. Para isso, usei o REMAP_TABLESPACE, até aí sem nenhum segredo.

Porém, como faria para que as tabelas fossem criadas comprimidas?

O atributo de COMPRESS, geralmente usado nas tabelas não tinha como ser mudado na hora do import.

As alternativas eram:

1 – Importar assim mesmo e fazer um Redefinition depois.

2 – Fazer o import com METADATA_ONLY e mudar as tabelas para COMPRESS, só que desse jeito os índices vão junto e na hora do import com os dados (DATA_ONLY) vai demora muito mais, estoura UNDO etc.

3 – Gerar o script de criação das tabelas, uma por uma, e criar manualmente apenas a tabela na nova tablespace e com COMPRESS e só depois soltar o IMPDP.

 

Baseado nas possibilidades pensadas… A alternativa mais interessante e que resolvia era a 3, mas ia dar um trabalho enorme…. uma a uma, criar na mão…. muito trabalho!

Um dos dons (se bem usado) do ser humano é a “preguiça produtiva”, e usei deste dom… em vez de fazer assim, saí pesquisando.

Nas buscas, descobri então que o atributo de COMPRESS pode ser como default na tablespace… Aí sim… só criar a tablespace e informar a cláusula: “…default compress for oltp”, e toda tabela criada na tablespace que não informar nada sobre compressão, será assumida a compressão da tablespace! Aêêêê!!! Resolveu!  \o/

Só que não!

Fiz o import, e ao verificar as tabelas, todas estavam sem compressão! Mesmo a tablespace estando com o default COMPRESSION FOR OLTP.

Dica: Se você tem dúvida de como verifica isso na tabela, assim é possível: select table_name, compression, compress_for from dba_tables where owner='SEU_OWNER_AQUI'

Quebrou meu esquema!

Lá vem a preguiça voltando novamente e lá vou eu pesquisar novamente.

Gastei mais um tempo de pesquisa e descobri o porquê das tabelas não obedecerem ao default da tablespace, lembram quando falei lá em cima: “e toda tabela criada na tablespace que não informar nada sobre compressão”, pois é…. SE não informar nada! Só que quando o expdp é feito, o script gerado de criação da tabela vem com o atributo NOCOMPRESS, porque no banco de origem a tabela de fato não era comprimida, na hora do import a tabela era criada com o atributo original contido no script, NOCOMPRESS!

Voltamos então para a solução 3, gerando o script dos create table, mudando o script de cada uma das tabelas e criando todas as tabelas manualmente, com COMPRESS… mas minha preguiça produtiva é resistente e resiliente… pesquisei mais um pouco, para fazer de forma mais inteligente… e achei o tal atributo TRANSFORM do IMPDP!

Vamos lá… no IMPDP, com o TRANSFORM, você pode exatamente mudar atributos dos objetos a serem criados na hora do IMPDP, ficando diferente do que foi gerado no banco de origem.

Para o meu caso, eu precisava apenas remover o tal NOCOMPRESS do script de criação, e dizer para o banco que as tabelas deveriam ir para uma tablespace nova, isso é possível adicionando as seguintes clausulas, combinadas, no meu comando de IMPDP:

...transform=segment_attributes:n remap_tablespace=TBS_OLD:TBS_NEW_COMPRESS...

Desta forma, os atributos do segmento que estavam no banco antigo (e no script do IMPDP) não serão utilizados, fazendo com que o default da nova tablespace seja usado.

E a preguiça vence novamente!! Tabelas criadas com COMPRESS FOR OLTP e import rolando.

Espero que seja útil para vocês.

Podemos usar isso, por exemplo, nos refresh de bases que fazemos com EXPDP/IMPDP, devemos economizar uma área razoável nas bases de desenvolvimento e homologação com esse método.

É uma ideia!

As notas que encontrei nas pesquisas foram:

Internet:

http://www.dba-oracle.com/t_impdp_transform_segment_attributes.htm

https://docs.oracle.com/cd/E11882_01/server.112/e22490/dp_import.htm#SUTIL939

Metalink:

How To Import The Non-Compressed Tables Into A Compressed Tablespace And Obtain Compress Target Tables? (Doc ID 2174751.1)

E….. só para constar, vi que no 12c, tem muito mais atributos que poderão ser usados com o TRANSFORM, como pode exemplo, não precisar ter default da tablespace, no próprio comando de IMPDP poderemos substituir o valor dos parâmetros, por exemplo, trocar o NOCOMPRESS por COMPRESS FOR OLTP, vejam mais detalhes aqui:

https://docs.oracle.com/database/121/SUTIL/GUID-64FB67BD-EB67-4F50-A4D2-5D34518E6BDB.htm#SUTIL939

 

É isso gente.

Espero ter ajudado!

 

Abraços!

Cursos Oficiais Oracle com desconto

Fala PessoAll,

Atendendo ao pedido de um leitor do Site, o amigo Lander Poolk S. Herrera estou publicando estas ofertas da Oracle para cursos oficiais.

Tem diversos cursos interessantes e com descontos bem convidativos. Talvez seja a sua chance de fazer um curso oficial pagando menos ou sua chance de conseguir convencer seu chefe a liberar a verba para seu treinamento.

Só lembrando que para tornar-se OCP você precisa obrigatoriamente ter um curso oficial, então, é uma chance de já atender a este requisito.

Este é o link da Oracle sobre os treinamentos, tem tudo detalhado, turmas, descontos, etc.

Noticias sobre Capacitación y Certificación Oracle Database

 

Como dica: Acabei de fazer um treinamento oficial em São Paulo, no Centro de Treinamento En-Sof. O centro é bem interessante, tem uma boa estrutura, salas agradáveis e com bons equipamentos.

Além do local, o que interessa muito em um treinamento é o instrutor. O material a ser seguido e o ambiente do curso é tudo “engessado” pela Oracle, o que vai fazer a diferença é o instrutor que pode ser um simples “Leitor de slides” , ou pode ser um cara de mercado, com conhecimento e boa didática. Portanto, antes de fazer o treinamento, procure saber quem é o instrutor, pegue referências dele e verifique se é uma boa “aquisição”.

 

Abraços a todos!

 

Atc.

Gerson Júnior

gerson.vasconcelos@gmail.com

Erro na Instalação – 10.2.0.1 – OUI-10094

Olá PessoALL,

Ontem tive uma necessidade de instalação do Oracle 10gR2 em um cliente. Isso mesmo, estamos em 07/2013, e precisamos instalar um Oracle 10gR2! rsrs. Deixa eu contar um pouco da história:

O banco de produção é um 9.2.0.6 (acharam que não podia ser pior que o 10gR2 né), rodando em um HP-UX Itanium 64bits e que não tem mais suporte por parte da HP, ou seja, temos que nos virar com o que temos para migrar este banco de 9.2.0.6 urgente! Afinal, não temos mais suporte nem do banco nem da máquina onde ele está instalado. Depois de muitas e muitas tentativas de migração, inclusive usando Golden Gate em que não tivemos sucesso, a opção menos pior encontrada foi expdp e impdp, só que para isso precisávamos estar pelo menos no 10g! Sei que deve estar se perguntando… porque não 11g direto? Lembram que a máquina não tem mais suporte? Pois é, para instalar o 11g neste servidor, mesmo sendo certificado, precisava instalar alguns pacotes, e claro que sem suporte, sem contrato e sem nada, a HP não iria dar de mão beijada estes pacotes para nos ajudar a deixar de usar a plataforma deles! Por isso a escolha do passo a passo foi:

1 – Instalar o Oracle 10GR2, 10.2.0.1.

2 – Aplicar o Patchset 10.2.0.4 e eliminar alguns possíveis bugs.

3 – Migrar o banco 9.2.0.6 para 10.2.0.4.

4 – Fazer expdp paralelizado para extrair os dados.

5 – Fazer impdp no novo, querido e parrudo servidor Linux com Oracle 11gR2!

Então, já no passo 1 encontramos um problema, o erro: OUI-10094.

A instalação ocorria normalmente, todas as configurações eram feitas e dava erro apenas na hora de registrar no inventário.

Pois é, na parte mais simples ocorria o erro.

Pesquisando no Metalink, encontrei uma nota que falava a respeito, em que a Oracle assumia sem nenhum pudor que o instalador do 10.2.0.1, versão base do 10gR2 tinha um “bug” que não conseguia fazer atualização de inventário caso tivessem outros Oracle Home´s  instalados com outros owners na mesma máquina. Por exemplo:

Tenho um Oracle 9.2.0.6 instalado com o owner ora96.

Tenho um Oracle 10gR1 instalado com o owner ora101.

No momento de instalar o Oracle 10gR2 com o owner ora102, ele vai ter que adicionar no inventário esta nova instalação, mas… quem criou o inventário não foi o owner ora102, por isso ocorre o problema, mas é um problema no instalador.

O grande aprendizado que quero passar neste post é sobre a recomendação da Oracle para corrigir o problema, que basicamente foi: “Instale o Oracle 10.2.0.1 com o instalador do 10.2.0.4!”, então, na hora de chamar o runInstaller, usar o executável da versão 10.2.0.4 chamando a instalação do 10.2.0.1. Como fazer isso… assim:


[ora10g@srvhp:/home/ora10g]: cd /ora10g/install/patch_10204/disk1/
[ora10g@srvhp:/home/ora10g]: ./runInstaller FROM_LOCATION="/ora10g/install/10201/disk1/stage/products.xml"

Então, o que fizemos foi ir até a pasta de instalação do Patchset 10.2.0.4 e chamar o instalador dele, só que informando que a instalação deveria pegar os produtos da versão base 10.2.0.1, usando o parâmetro FROM_LOCATION. Interessante não?! Você pode instalar um outro “produto” usando o instalador menos “bugado”.

A conclusão disso pra mim é: Que bom que a Oracle é muito boa de documentação, porque esses probleminhas tem de monte! Só que tudo tá documentado e geralmente tem uma solução de contorno!

Temos então nosso 10gR2 instalado e agora vamos a migração! Caso tenhamos mais novidades, mantenho vocês informados!

 

Abraços a todos.

 

 

Atc.

Gerson Júnior

gerson.vasconcelos@gmail.com

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:UsersGersonJr>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:UsersGersonJr>

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


C:UsersGersonJr>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:UsersGersonJr>

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

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

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)

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

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