<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>glufke.net</title>
	<atom:link href="https://glufke.net/feed/" rel="self" type="application/rss+xml" />
	<link>https://glufke.net</link>
	<description></description>
	<lastBuildDate>Thu, 03 Sep 2020 22:28:46 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.8.6</generator>
	<item>
		<title>Novo curso de SQL Tuning da Nerv: EU FUI</title>
		<link>https://glufke.net/2015/02/novo-curso-de-sql-tuning-da-nerv-eu-fui/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Wed, 25 Feb 2015 12:44:41 +0000</pubDate>
				<category><![CDATA[DBA]]></category>
		<category><![CDATA[Evento]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Tuning]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=828</guid>

					<description><![CDATA[Estou escrevendo esse texto para colocar meu parecer sobre o novo curso de SQL Tuning oferecido pela Nerv. Como eu participei da primeira turma de SQL Tuning, tenho o privilégio de compartilhar sobre o curso de antemão. Este é o segundo curso que eu faço na Nerv. O primeiro, você pode ver o review neste [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Estou escrevendo esse texto para colocar meu parecer sobre o <strong>novo curso de SQL Tuning</strong> oferecido pela Nerv. Como eu participei da primeira turma de SQL Tuning, tenho o privilégio de compartilhar sobre o curso de antemão. Este é o segundo curso que eu faço na Nerv. O primeiro, você pode ver o <a href="https://glufke.net/oracle/viewtopic.php?t=7735">review neste link</a>.</p>
<h3>Instrutor</h3>
<p>O professor é o <a href="http://www.nervinformatica.com.br/instrutores.php">Ricardo Portilho Proni</a> que é uma referência técnica no Brasil. Para quem não conhece, ele possui uma grande quantidade de certificações, incluindo Oracle ACE e palestrante em diversos eventos sobre Oracle. Possui uma experiência profissional muito grande. Sou totalmente suspeito em falar sobre o Portilho, pois quem me conhece, sabe que eu sou fã de carteirinha dele desde 2010. <img src="https://s.w.org/images/core/emoji/13.1.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><a href="https://glufke.net/wp-content/uploads/2015/02/Nerv11.jpg"><img loading="lazy" class="alignleft wp-image-835" src="/wp-content/uploads/2015/02/Nerv11-300x196.jpg" alt="Nerv1" width="269" height="176" srcset="https://glufke.net/wp-content/uploads/2015/02/Nerv11-300x196.jpg 300w, https://glufke.net/wp-content/uploads/2015/02/Nerv11-1024x669.jpg 1024w, https://glufke.net/wp-content/uploads/2015/02/Nerv11-900x588.jpg 900w, https://glufke.net/wp-content/uploads/2015/02/Nerv11.jpg 1842w" sizes="(max-width: 269px) 100vw, 269px" /></a><a href="/wp-content/uploads/2015/02/Nerv2.jpg"><img loading="lazy" class="alignleft size-medium wp-image-836" src="/wp-content/uploads/2015/02/Nerv2-300x176.jpg" alt="Nerv2" width="300" height="176" srcset="https://glufke.net/wp-content/uploads/2015/02/Nerv2-300x176.jpg 300w, https://glufke.net/wp-content/uploads/2015/02/Nerv2-1024x601.jpg 1024w, https://glufke.net/wp-content/uploads/2015/02/Nerv2-900x528.jpg 900w" sizes="(max-width: 300px) 100vw, 300px" /></a><a href="/wp-content/uploads/2015/02/Nerv3.jpg"><img loading="lazy" class="alignnone wp-image-837" src="/wp-content/uploads/2015/02/Nerv3-300x177.jpg" alt="Nerv Certificados" width="297" height="176" srcset="https://glufke.net/wp-content/uploads/2015/02/Nerv3-300x177.jpg 300w, https://glufke.net/wp-content/uploads/2015/02/Nerv3-1024x606.jpg 1024w, https://glufke.net/wp-content/uploads/2015/02/Nerv3-900x533.jpg 900w" sizes="(max-width: 297px) 100vw, 297px" /></a></p>
<h3>A Turma</h3>
<p>Tive a grande alegria de re-encontrar amigos e conhecer novos. Na turma estavam os seguintes alunos:<br />
<strong>* Fernando Franquini</strong> (DBA Capin do <a href="http://certificacaobd.com.br">certificacaobd.com.br</a>. Atualmente DBA na Softplan )<br />
<strong>* Eduardo Ribeiro </strong>( DBA na UOL Diveo )<br />
<strong>* Hugo Torralbo</strong> ( DBA no Itaú / Unibanco )<br />
<strong>* Itagyba Kuhlmann</strong> ( Arquiteto de soluçoes na Pernambucanas )<br />
<strong>* Thomas Glufke </strong>( Oracle EBS Senior Developer na Dell Computers )<br />
<strong>*</strong> Abaixo, o instrutor <strong>Ricardo Portilho</strong> ( Instrutor e Owner da Nerv Informática )<br />
<span id="more-828"></span><br />
<a href="/wp-content/uploads/2015/02/nerv.jpg"><img loading="lazy" class="size-full wp-image-830" src="/wp-content/uploads/2015/02/nerv.jpg" alt="Turma SQL Tuning" width="512" height="302" srcset="https://glufke.net/wp-content/uploads/2015/02/nerv.jpg 1024w, https://glufke.net/wp-content/uploads/2015/02/nerv-300x177.jpg 300w, https://glufke.net/wp-content/uploads/2015/02/nerv-900x531.jpg 900w" sizes="(max-width: 512px) 100vw, 512px" /></a></p>
<h3>O curso</h3>
<p>São três dias de treinamento, alternando entre teoria, exemplos práticos, laboratório e muita troca de experiência. Como sempre, turmas pequenas.</p>
<p>O assunto Tuning é quase sempre um tabu, pois muita coisa pode afetar o comportamento do Oracle, mesmo em ambientes idênticos. É bem comum o profissional simplesmente &#8220;ir testando&#8221; algumas coisas pra ver se melhora a performance. É neste momento que o curso faz a diferença!</p>
<p>Como o Portilho mesmo disse, se o curso fosse sobre carros, &#8220;<em>eu não vou te ensinar a pilotar, eu vou te ensinar a ser um mecânico!</em>&#8220;. Isso é realmente verdade. O curso não é baseado em dicas, ou seja, receitas de bolo: &#8220;Se isso, faça aquilo&#8221;. É totalmente voltado ao funcionamento do otimizador, plano de execução, funcionamento e comportamento de índices e estatísticas, etc.</p>
<p>É realmente impressionante fazer um TRACE do otimizador e ver o que ele faz pra decidir qual plano de execução vai optar, e todas transformações que uma query sofre. Com os tópicos que estudamos, é possível analisar o motivo da demora e ajustá-las para ganhar performance.</p>
<p>Se você quiser saber mais detalhes de todos assuntos que são abordados, veja o <a href="http://www.nervinformatica.com.br/otsql.php">link do curso aqui</a>.</p>
<h3>Opinião Pessoal</h3>
<p>Já fiz alguns cursos de Tuning, mas até hoje nenhum deles foi tão aprofundado no assunto. Eu diria que o curso é voltado tanto pra DBAs como para desenvolvedores. É ideal se você já conhece algumas coisas sobre o assunto e quer ir mais a fundo.</p>
<p>Se você tiver a oportunidade de ir pra São Paulo e fazer este treinamento, tenho certeza que será um grande investimento e um upgrade na sua carreira.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Usar parâmetro na query com NVL</title>
		<link>https://glufke.net/2015/02/usar-parametro-na-query-com-nvl/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Tue, 10 Feb 2015 12:44:57 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Curiosidade]]></category>
		<category><![CDATA[SQL*Plus]]></category>
		<category><![CDATA[Utilidade]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=802</guid>

					<description><![CDATA[Tem algumas coisas que estão praticamente enraizadas no mundo Oracle: me refiro a algumas práticas que quase todo mundo faz e que foi adotado como padrão. O texto abaixo não contém nenhuma nova feature do Oracle, nem é nenhuma novidade pra ninguém. Mas por incrível que pareça, eu vejo em quase todas empresas essa prática [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="/wp-content/uploads/2015/02/bug.png"><img loading="lazy" class="alignleft wp-image-817" src="/wp-content/uploads/2015/02/bug.png" alt="bug" width="845" height="119" srcset="https://glufke.net/wp-content/uploads/2015/02/bug.png 488w, https://glufke.net/wp-content/uploads/2015/02/bug-300x42.png 300w" sizes="(max-width: 845px) 100vw, 845px" /></a></p>
<p>Tem algumas coisas que estão praticamente enraizadas no mundo Oracle: me refiro a algumas práticas que quase todo mundo faz e que foi adotado como padrão. O texto abaixo não contém nenhuma nova feature do Oracle, nem é nenhuma novidade pra ninguém. Mas por incrível que pareça, eu vejo em quase todas empresas essa prática e isso normalmente gera problemas. Me refiro a <strong>utilização de um NVL pra fazer um filtro opcional</strong> na query. Abaixo está um exemplo:</p>
<pre class="brush: sql;">SELECT *
FROM tabela
WHERE campo = NVL ( p_parametro1 , campo )</pre>
<p>Quase todo programa tem um sistema de filtro como esse acima.<br />
Se o usuário informar o <strong>p_parametro1</strong>, a query vai mostrar apenas as linhas cujo <strong>campo</strong> é igual ao <strong>p_parametro1</strong>.<br />
Se o usuário não informar nada, cai no NVL, e ele faz join com a própria coluna, trazendo tudo.<br />
<span id="more-802"></span></p>
<p>Aqui está um exemplo real do que foi citado acima.<br />
Primeiro, vamos criar uma BIND variável no SQL*Plus, chamada PARJOB, que será o parâmetro da nossa query:</p>
<pre class="brush: plain;">SQL&gt; var parjob VARCHAR2(100)
SQL&gt; var
variable parjob
datatype VARCHAR2(100)
 
SQL&gt;</pre>
<p>Agora, vamos rodar uma query usando o sistema de NVL pra filtrar. Detalhe, o parâmetro está NULO!</p>
<pre class="brush: plain;">SQL&gt; SELECT *
  2  FROM emp
  3  WHERE job = NVL ( :parjob, job)
  4  /
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7839 KING       PRESIDENT       17-Nov-1981   5000.00               10
 7698 BLAKE      MANAGER    7839 01-May-1981   2850.00               40
 7782 CLARK      MANAGER    7839 09-Jun-1981   2450.00               10
 7566 JONES      MANAGER    7839 02-Apr-1981   2975.00               20
 7788 SCOTT      ANALYST    7566 19-Apr-1987   3000.00               20
 7902 FORD       ANALYST    7566 03-Dec-1981   3000.00               20
 7369 SMITH      CLERK      7902 17-Dec-1980    800.00               20
 7499 ALLEN      SALESMAN   7698 20-Feb-1981   1600.00    300.00     30
 7521 WARD       SALESMAN   7698 22-Feb-1981   1250.00    500.00     30
 7654 MARTIN     SALESMAN   7698 28-Sep-1981   1250.00   1400.00     30
 7844 TURNER     SALESMAN   7698 08-Sep-1981   1500.00      0.00     30
 7876 ADAMS      CLERK      7788 23-May-1987   1100.00               20
 7900 JAMES      CLERK      7698 03-Dec-1981    950.00               30
 7934 MILLER     CLERK      7782 23-Jan-1982   1300.00               20
 
14 rows selected
parjob
---------
 
SQL&gt;</pre>
<p>Repare que todas as 14 linhas da EMP vieram corretamente.<br />
Caso a gente setar um valor pro parâmetro, ele deve filtrar.</p>
<pre class="brush: plain;">SQL&gt; begin
  2    :parjob := 'MANAGER';
  3  end;
  4  /
 
PL/SQL procedure successfully completed
parjob
---------
MANAGER
 
SQL&gt;</pre>
<p>Se executarmos novamente a mesma query, vai funcionar o filtro:</p>
<pre class="brush: plain;">SQL&gt; SELECT *
  2  FROM emp
  3  WHERE job = NVL ( :parjob, job)
  4  /
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7698 BLAKE      MANAGER    7839 01-May-1981   2850.00               40
 7782 CLARK      MANAGER    7839 09-Jun-1981   2450.00               10
 7566 JONES      MANAGER    7839 02-Apr-1981   2975.00               20
parjob
---------
MANAGER
 
SQL&gt;</pre>
<p>Funcionou perfeitamente: Trouxe apenas as linhas MANAGER, conforme o filtro.</p>
<p><strong>Afinal, qual é o problema disso?</strong><br />
Essa prática pode começar a gerar resultados errados, bugs e dor de cabeça sem fim.<br />
Isso porque usar o NVL dessa forma <strong>só funciona quando nenhuma linha é NULL</strong>. E é nisso que as pessoas erram. Usam essa forma de fazer filtro sempre, sem consultar se o campo poder ter NULLs ou não.</p>
<p>Vamos fazer o mesmo exemplo para o campo MGR, que é um campo que contém nulos. Vamos criar outra variável BIND e vamos usar ela no filtro do gerente. (MGR)</p>
<pre class="brush: plain;">SQL&gt; var parmgr NUMBER;
SQL&gt; var
variable parjob
datatype VARCHAR2(100)
 
variable parmgr
datatype NUMBER
 
SQL&gt;</pre>
<p>Pra testar, vamos setar um valor:</p>
<pre class="brush: plain;">SQL&gt; begin 
  2    :parmgr := 7839;
  3  end;
  4  /
 
PL/SQL procedure successfully completed
parmgr
---------
7839
 
SQL&gt; 
SQL&gt; 
SQL&gt; SELECT *
  2  FROM emp
  3  WHERE mgr = NVL ( :parmgr, mgr)
  4  /
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7698 BLAKE      MANAGER    7839 01-May-1981   2850.00               40
 7782 CLARK      MANAGER    7839 09-Jun-1981   2450.00               10
 7566 JONES      MANAGER    7839 02-Apr-1981   2975.00               20
parmgr
---------
7839
 
SQL&gt;</pre>
<p>Até aqui funcionou! Trouxe apenas as linhas que o MGR é 7839.<br />
Mas e se deixar nulo o parâmetro? Deve trazer todas linhas, certo?</p>
<pre class="brush: plain;">SQL&gt; begin
  2    :parmgr := NULL;
  3  end;
  4  /
 
PL/SQL procedure successfully completed
parmgr
---------
 
SQL&gt; 
SQL&gt; SELECT *
  2  FROM emp
  3  WHERE mgr = NVL ( :parmgr, mgr)
  4  /
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7698 BLAKE      MANAGER    7839 01-May-1981   2850.00               40
 7782 CLARK      MANAGER    7839 09-Jun-1981   2450.00               10
 7566 JONES      MANAGER    7839 02-Apr-1981   2975.00               20
 7788 SCOTT      ANALYST    7566 19-Apr-1987   3000.00               20
 7902 FORD       ANALYST    7566 03-Dec-1981   3000.00               20
 7369 SMITH      CLERK      7902 17-Dec-1980    800.00               20
 7499 ALLEN      SALESMAN   7698 20-Feb-1981   1600.00    300.00     30
 7521 WARD       SALESMAN   7698 22-Feb-1981   1250.00    500.00     30
 7654 MARTIN     SALESMAN   7698 28-Sep-1981   1250.00   1400.00     30
 7844 TURNER     SALESMAN   7698 08-Sep-1981   1500.00      0.00     30
 7876 ADAMS      CLERK      7788 23-May-1987   1100.00               20
 7900 JAMES      CLERK      7698 03-Dec-1981    950.00               30
 7934 MILLER     CLERK      7782 23-Jan-1982   1300.00               20
 
13 rows selected
parmgr
---------
 
SQL&gt;</pre>
<p>Só veio 13 linhas? Onde está a linha do KING ? Faltando uma linha! Justamente aquela que está NULA!<br />
Por isso essa prática é péssima. Você só pode usar NVL pra fazer filtro dessa forma quando tiver certeza absoluta que não existem valores NULL na coluna.</p>
<p><strong>SOLUÇÃO PRÁTICA</strong></p>
<p>Em vez de usar NVL, basta usar um simples OR:</p>
<pre class="brush: plain; highlight: [8]">SQL&gt; SELECT *
  2  FROM emp
  3  WHERE ( :parmgr IS NULL OR mgr=:parmgr )
  4  /
 
EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7839 KING       PRESIDENT       17-Nov-1981   5000.00               10
 7698 BLAKE      MANAGER    7839 01-May-1981   2850.00               40
 7782 CLARK      MANAGER    7839 09-Jun-1981   2450.00               10
 7566 JONES      MANAGER    7839 02-Apr-1981   2975.00               20
 7788 SCOTT      ANALYST    7566 19-Apr-1987   3000.00               20
 7902 FORD       ANALYST    7566 03-Dec-1981   3000.00               20
 7369 SMITH      CLERK      7902 17-Dec-1980    800.00               20
 7499 ALLEN      SALESMAN   7698 20-Feb-1981   1600.00    300.00     30
 7521 WARD       SALESMAN   7698 22-Feb-1981   1250.00    500.00     30
 7654 MARTIN     SALESMAN   7698 28-Sep-1981   1250.00   1400.00     30
 7844 TURNER     SALESMAN   7698 08-Sep-1981   1500.00      0.00     30
 7876 ADAMS      CLERK      7788 23-May-1987   1100.00               20
 7900 JAMES      CLERK      7698 03-Dec-1981    950.00               30
 7934 MILLER     CLERK      7782 23-Jan-1982   1300.00               20
 
14 rows selected
parmgr
---------
 
SQL&gt;</pre>
<p>Dessa forma você não precisa se preocupar se existe NULL ou não no campo. Uma preocupação a menos.</p>
<p>Obviamente, não estamos fazendo testes relacionados ao plano de execução, visto que o resultado das duas queries é diferente: Uma não traz NULLS e outra traz. O uso do NVL certamente é mais performático quando usando num campo com índice, pois ele não precisa percorrer a tabela buscando os NULLS e utiliza o índice). Como são resultados diferentes, não temos porque comparar performance.</p>
<p>Caso você queria saber mais sobre campos NULL, comparação de NULLs, aqui tem alguns textos e experimentos realizados pela comunidade:<br />
<a href="https://glufke.net/2007/09/06/comparacao-de-campos-com-null/" target="_blank" rel="noopener noreferrer">Comparação de campos com null</a><br />
<a href="https://glufke.net/oracle/viewtopic.php?t=2153" target="_blank" rel="noopener noreferrer">Null é igual a branco ?</a><br />
<a href="https://glufke.net/oracle/viewtopic.php?p=357" target="_blank" rel="noopener noreferrer">Interessante &#8211; Campo NULL</a><br />
<a href="https://glufke.net/oracle/viewtopic.php?f=3&amp;t=2012" target="_blank" rel="noopener noreferrer">Igualdade Desigual ??? alguém sabe porque NULL não é igual a NULL?</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Estudo de Caso: Relatório com Linhas Duplicadas</title>
		<link>https://glufke.net/2014/08/estudo-de-caso-relatorio-com-linhas-duplicadas/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Tue, 19 Aug 2014 20:11:37 +0000</pubDate>
				<category><![CDATA[ERP]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[Estudo de Caso]]></category>
		<category><![CDATA[Relatório]]></category>
		<category><![CDATA[Sessão]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=586</guid>

					<description><![CDATA[Este é mais um daqueles casos que temos que chamar o Padre Quevedo pra dizer: &#8220;Este fenômeno nôm exziste&#8220;. Abaixo, vamos fazer uma análise de um programa com erro e como foi solucionado o erro. O PROBLEMA O relatório funcionava perfeitamente. Mas raramente, ou seja, 1% das vezes em que era executado, o relatório saía [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="/wp-content/uploads/2014/08/report_error2.png"><img loading="lazy" class="aligncenter wp-image-732" src="/wp-content/uploads/2014/08/report_error2.png" alt="report_error2" width="865" height="94" srcset="https://glufke.net/wp-content/uploads/2014/08/report_error2.png 943w, https://glufke.net/wp-content/uploads/2014/08/report_error2-300x32.png 300w, https://glufke.net/wp-content/uploads/2014/08/report_error2-940x102.png 940w, https://glufke.net/wp-content/uploads/2014/08/report_error2-900x97.png 900w" sizes="(max-width: 865px) 100vw, 865px" /></a></p>
<p>Este é mais um daqueles casos que temos que chamar o Padre Quevedo pra dizer: &#8220;<em>Este fenômeno nôm exziste</em>&#8220;. Abaixo, vamos fazer uma análise de um programa com erro e como foi solucionado o erro.</p>
<h3>O PROBLEMA</h3>
<p>O relatório funcionava perfeitamente. Mas <em>raramente</em>, ou seja, 1% das vezes em que era executado, <span style="text-decoration: underline;">o relatório saía com os valores de todos os campos duplicados!</span> Exemplo: &nbsp;Deveria sair o valor R$ 20,00 &nbsp;mas saía R$ 40,00. Isso ocorria em todas colunas!<br />
<span id="more-586"></span></p>
<h3>FUNCIONAMENTO DO RELATÓRIO</h3>
<p>O usuário informa os parâmetros em uma sessão do Oracle Forms. (Concorrente do Oracle EBS)<br />
O relatório é gerado por uma procedure em uma outra sessão, e insere as linhas em uma tabela comum do Oracle.<br />
Nesta tabela existe um campo chamado SESSAO onde é gravado o SESSION_ID que é passado via parâmetro. (A mesma sessão do Oracle Forms). Dessa forma, vários usuários podem executar o relatório ao mesmo tempo que o programa sempre filtra pela sessão, assim cada um só vê o que é seu, pois cada usuário está numa sessão diferente do Forms.</p>
<p>Ou seja, após disparar o relatório, a procedure é executada em background (é disparado um concorrente do Oracle EBS, que é basicamente, uma sessão do banco executando o programa).</p>
<p>O programa funcionava basicamente em 4 etapas:</p>
<p>1. A procedure limpa a tabela onde os dados serão inseridos e dá um COMMIT. Basicamente, roda um</p>
<pre class="brush: sql;">DELETE FROM tabela WHERE SESSAO=p_sessao;
COMMIT;</pre>
<p>2. Procedure roda diversos cursores inserindo nessa tabela. (cada cursor demora +ou- um minuto).<br />
É gravado nessa tabela o número da sessão corrente do Oracle passada via parâmetro.<br />
3. COMMIT;<br />
4. É disparado uma outra sessão (XML Publisher) que monta o relatório com base nos valores inseridos.<br />
Novamente, é passado o número SESSION_ID via parâmetro e o relatório mostra apenas o que é da sessão do usuário que informou os parâmetros.</p>
<h3>O que ocorria para dar as linhas duplicadas</h3>
<p>O erro ocorria quando o mesmo usuário executava duas vezes o relatório em um curto espaço de tempo.<br />
Dessa forma, o seguinte &#8220;fenômeno&#8221; era realizado:</p>
<table style="width: 800px;" border="1" cellspacing="0" cellpadding="1">
<tbody>
<tr>
<td>EXECUÇÃO 1</td>
<td>EXECUÇÃO 2</td>
<td>Explicação</td>
</tr>
<tr>
<td>É executado a limpeza da tabela e realizado Commit. (etapa1)</td>
<td>&nbsp;</td>
<td>Sem nenhum prolema até agora</td>
</tr>
<tr>
<td>Programa começa a executar os cursores e inserir na tabela com o número da sessão X.</td>
<td>&nbsp;</td>
<td>Este processo leva alguns minutos.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Programa executa a limpeza da tabela, mas não tem nada ainda, pois a outra sessão ainda não fez COMMIT nos dados inseridos!</td>
<td>Usuário disparou novamente o relatório, com parâmetros diferentes, mas é a mesma sessão do Oracle Forrms.</td>
</tr>
<tr>
<td>COMMIT;</td>
<td>&nbsp;</td>
<td>A primeira execução comitou.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Programa começa a executar os cursores e inserir na tabela com o número da sessão X.</td>
<td>Aqui ocorre a duplicidade</td>
</tr>
<tr>
<td>Dispara a execução do Relatório.</td>
<td>&nbsp;</td>
<td>Relatório sai corretamente.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>COMMIT;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>Dispara a execução do Relatório.</td>
<td>Essa execução vinha com dados duplicados!</td>
</tr>
</tbody>
</table>
<p><em>É interessante notar que caso o usuário rodasse o relatório em um periodo de tempo um pouco maior, ou seja, após o segundo COMMIT da primeira execução, o erro não aconteceria, pois o DELETE da segunda execução ia conseguir ver os dados inseridos na primeira execução e limpá-los corretamente.</em></p>
<h3>Correção do problema</h3>
<p>Após descoberto o que ocorria realmente, foi muito fácil solucionar o problema, pois em vez de se usar o número da sessão apenas, foi também concatenado a esse número outro número que não iria se repetir. Dessa forma, mesmo que o usuário executasse duas vezes o relatório, o número da sessão seria único e o problema não ocorreria.</p>
<p>Este é um exemplo real de bug encontrado em programa, que foi difícil achar o problema devido a raridade que o erro ocorria.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Bug do ano 2013</title>
		<link>https://glufke.net/2013/02/bug-do-ano-2013/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Mon, 25 Feb 2013 17:42:02 +0000</pubDate>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[2013]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[Datas]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=569</guid>

					<description><![CDATA[Pra quem pensa que o Bug do Milênio foi o último envolvendo datas, aí vai a sensação do momento: O Bug de 2013. O Bug ocorre na seguinte situação: * O programa X grava dados de data na tabela usando o seguinte formato de datas:  YYYYMMDD. * O programa Y lê dessa tabela usando o [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Pra quem pensa que o <a title="Bug do Milênio" href="http://pt.wikipedia.org/wiki/Problema_do_ano_2000">Bug do Milênio</a> foi o último envolvendo datas, aí vai a sensação do momento: O Bug de 2013.</p>
<p>O Bug ocorre na seguinte situação:<br />
* O programa X grava dados de data na tabela usando o seguinte formato de datas:  YYYYMMDD.<br />
* O programa Y lê dessa tabela usando o formato DDMMYYYY. (Sim, é um erro, um bug no programa).</p>
<p>Até o ano de 2012, este erro não aparecia, veja um exemplo:<br />
* O programa X salva a data <strong><span style="color: #ff0000;">23</span>&#8211;<span style="color: #339966;">abr</span>&#8211;<span style="color: #0000ff;">2011</span></strong> = <strong><span style="color: #0000ff;">2011</span><span style="color: #339966;">04</span><span style="color: #ff0000;">23</span></strong> (YYYYMMDD)<br />
* Quando essa data era lida pelo programa Y, ele lia  <strong><span style="color: #ff0000;">20</span><span style="color: #339966;">11</span><span style="color: #0000ff;">0423</span></strong> (DDMMYYYY) = <strong><span style="color: #ff0000;">20</span>&#8211;<span style="color: #339966;">nov</span>&#8211;<span style="color: #0000ff;">0423</span></strong>. Data errada, mas não acusava erro!</p>
<p>Pois o ano de 2013 chegou e esse erro apareceu. Veja:<br />
* O programa X salva a data <strong><span style="color: #ff0000;">23</span>&#8211;<span style="color: #339966;">abr</span>&#8211;<span style="color: #0000ff;">2013</span></strong> = <strong><span style="color: #0000ff;">2013</span><span style="color: #339966;">04</span><span style="color: #ff0000;">23</span></strong> (YYYYMMDD)<br />
* Quando essa data era lida pelo programa Y, ele lia  <strong><span style="color: #ff0000;">20</span><span style="color: #339966;">13</span><span style="color: #0000ff;">0423</span></strong> (DDMMYYYY) = <strong><span style="color: #ff0000;">20</span>-???-<span style="color: #0000ff;">0423</span></strong>. Como não existe mês 13, dá erro!</p>
<p>O interessante é que esse bug está aparecendo só agora, depois de muitos anos de erro oculto. Finalmente em 2013 ele está fazendo os programas pararem de rodar.</p>
<p><em>Exemplo/Situação compartilhada por<strong> Rafael Lopes Lima</strong> (Programador Oracle EBS)</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Utilizando o mesmo teclado/mouse para dois computadores</title>
		<link>https://glufke.net/2012/05/utilizando-o-mesmo-tecladomouse-para-dois-computadores/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Wed, 23 May 2012 13:26:50 +0000</pubDate>
				<category><![CDATA[Off Topic]]></category>
		<category><![CDATA[Mouse]]></category>
		<category><![CDATA[Synergy]]></category>
		<category><![CDATA[Teclado]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=544</guid>

					<description><![CDATA[Este é um texto off-topic, mas pode ser útil pra algumas pessoas. Aqui na empresa, prestamos serviço pra vários clientes. Um particularmente, exige que o trabalho seja feito no próprio notebook que eles fornecem. Nesse caso, eu tenho na minha mesa um PC (na esquerda) e um notebook (na direita), este, exclusivamente para uso de [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Este é um texto off-topic, mas pode ser útil pra algumas pessoas.</p>
<p>Aqui na empresa, prestamos serviço pra vários clientes. Um particularmente, exige que o trabalho seja feito no próprio notebook que eles fornecem. Nesse caso, eu tenho na minha mesa um PC (na esquerda) e um notebook (na direita), este, exclusivamente para uso de um cliente.</p>
<p>O problema é que isso gera uma série de incômodos, por exemplo:</p>
<ul>
<li>Quando conecto na VPN usando o notebook, acabo perdendo a conexão com a internet. Caso eu precise copiar algum script (aqui do site, por exemplo) tenho que desconectar da VPN ou copiar pra um pen-drive, etc.</li>
<li>Outro problema é o espaço na mesa. É um pouco desconfortavel usar 2 teclados, 2 mouses. Tem que girar os braços pra um lado ou pra outro (<em>fail</em>), e quase sempre eu me confundo e acabo usando o mouse errado (<em>double fail</em>).</li>
</ul>
<p><span id="more-544"></span></p>
<p>A solução pra tudo isso: Um programa chamado <a title="Synergy" href="http://synergy-foss.org/pt-br/" target="_blank" rel="noopener noreferrer">SYNERGY</a>, que é open-source, free, etc.</p>
<p>O Synergy possibilita que um teclado e um mouse possa ser usados em 2 ou mais computadores!</p>
<p><strong>Como funciona</strong></p>
<p>Você instala o Synergy em todos computadores que você quer usar o teclado. No meu caso:</p>
<p>No PC, eu instalei e ativei ele como SERVER.<br />
No notebook, eu instalei e ativei ele como CLIENTE, neste caso, eu precisei colocar o IP do meu PC &#8211; que é onde está o server.</p>
<p style="text-align: center;"><a href="/wp-content/uploads/2012/05/synergy.jpg"><img loading="lazy" class="aligncenter size-full wp-image-545" title="Synergy" src="/wp-content/uploads/2012/05/synergy.jpg" alt="" width="454" height="210" srcset="https://glufke.net/wp-content/uploads/2012/05/synergy.jpg 648w, https://glufke.net/wp-content/uploads/2012/05/synergy-300x138.jpg 300w" sizes="(max-width: 454px) 100vw, 454px" /></a></p>
<p><strong>Benefícios</strong></p>
<ul>
<li>Basta ir com o mouse pra direita da tela, que o mouse &#8220;entra&#8221; no outro computador, como se fosse um único PC com tela estendida! Ou seja, posso usar agora o mesmo mouse e teclado pra ambos!</li>
<li>É possível copiar um texto no PC e colar o texto no notebook! Então, mesmo com a VPN ligada que eu perdia o acesso a internet, eu consigo copiar do email, de sites e colar lá.</li>
</ul>
<p>Neste caso, o Synergy se mostrou extremamente eficiente, e por isso achei que valia a pena compartilhar.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fazendo Rateio através de Funções Analíticas</title>
		<link>https://glufke.net/2012/04/fazendo-rateio-atraves-de-funcoes-analiticas/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Wed, 11 Apr 2012 20:43:50 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Analíticas]]></category>
		<category><![CDATA[Funções]]></category>
		<category><![CDATA[Matemática]]></category>
		<category><![CDATA[Rateio]]></category>
		<category><![CDATA[Utilidade]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=508</guid>

					<description><![CDATA[Neste post, vamos mostrar como utilizar funções analíticas para fazer o rateio de um valor em diversas linhas de uma tabela. Primeiro, vamos criar a tabela de teste: CREATE TABLE glufke_teste (nro_nota NUMBER, item NUMBER, valor NUMBER); INSERT INTO glufke_teste VALUES ( 50, 1, 1.45); INSERT INTO glufke_teste VALUES ( 50, 2, 3.91); INSERT INTO [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="/wp-content/uploads/2012/04/rateio.jpg"><img loading="lazy" class="size-full wp-image-533 alignright" title="Rateio" src="/wp-content/uploads/2012/04/rateio.jpg" alt="" width="89" height="90" srcset="https://glufke.net/wp-content/uploads/2012/04/rateio.jpg 185w, https://glufke.net/wp-content/uploads/2012/04/rateio-150x150.jpg 150w" sizes="(max-width: 89px) 100vw, 89px" /></a>Neste post, vamos mostrar como utilizar <strong>funções analíticas</strong> para fazer o rateio de um valor em diversas linhas de uma tabela.</p>
<p>Primeiro, vamos criar a tabela de teste:</p>
<pre class="brush: sql;">CREATE TABLE glufke_teste
(nro_nota  NUMBER, item NUMBER, valor NUMBER);
INSERT INTO glufke_teste VALUES ( 50, 1, 1.45);
INSERT INTO glufke_teste VALUES ( 50, 2, 3.91);
INSERT INTO glufke_teste VALUES ( 50, 3, 5.04);</pre>
<pre class="brush: plain;">SQL&gt; SELECT * FROM glufke_teste;

  NRO_NOTA       ITEM      VALOR
---------- ---------- ----------
        50          1       1,45
        50          2       3,91
        50          3       5,04

SQL&gt;</pre>
<p>Nosso objetivo é ratear um valor proporcionalmente nessas linhas. Como exemplo prático, vamos distribuir o valor R$ 49,30!<span id="more-508"></span></p>
<p>Sabemos que a soma das 3 linhas é 10,40:</p>
<pre class="brush: plain;">SQL&gt; SELECT SUM(VALOR) FROM GLUFKE_TESTE;

SUM(VALOR)
----------
      10,4

SQL&gt;</pre>
<p>Então, através de uma simples regra de 3, vemos o percentual de cada linha! Ou seja, temos que aplicar o valor de 49,30 conforme esses percentuais!</p>
<pre class="brush: plain;">SQL&gt; SELECT VALOR, VALOR/10.4*100 PERC FROM GLUFKE_TESTE;

     VALOR       PERC
---------- ----------
      1,45 13,9423076
      3,91 37,5961538
      5,04 48,4615384

SQL&gt;</pre>
<p>Com isso, basta colocar o valor 49.30 ali que temos distribuído! Repare que a soma do valor rateado é exatamente os 49,30 ! Ou seja, está distribuído conforme nossa necessidade!</p>
<pre class="brush: plain;">SQL&gt; select valor, valor/10.4* 49.3 vlr_rateado from glufke_teste;

     VALOR VLR_RATEADO
---------- -----------
      1,45 6,873557692
      3,91 18,53490384
      5,04 23,89153846

SQL&gt;</pre>
<h3>Usando funções analíticas pra obter esse resultado!</h3>
<p>Agora, usando a função analitica SUM, pra buscar &#8220;em tempo de execução&#8221; a soma da coluna valor (abaixo, a coluna TOTAL), e fazer o cálculo todo numa única tacada!</p>
<pre class="brush: sql;">SELECT
  nro_nota
, item
, valor
, sum(valor) over (order by nro_nota) total
, valor / sum(valor) over (order by nro_nota) * 49.3 vlr_rateado
FROM GLUFKE_teste
WHERE nro_nota = 50
/</pre>
<pre class="brush: plain;">  NRO_NOTA       ITEM      VALOR      TOTAL VLR_RATEADO
---------- ---------- ---------- ---------- -----------
        50          1       1,45       10,4 6,873557692
        50          2       3,91       10,4 18,53490384
        50          3       5,04       10,4 23,89153846

SQL&gt;</pre>
<p>Vamos adicionar mais um campo chamado VLR_ARR, que arredonda pra 2 casas decimais o valor rateado:</p>
<pre class="brush: sql;">SELECT
  nro_nota
, item
, valor
, sum(valor) over (order by nro_nota) total
, valor / sum(valor) over (order by nro_nota) * 50 vlr_rateado
, ROUND(   valor / sum(valor) over (order by nro_nota) * 49.3 ,2 ) vlr_arr
FROM glufke_teste
WHERE nro_nota = 50
/</pre>
<pre class="brush: plain;">  NRO_NOTA       ITEM      VALOR      TOTAL VLR_RATEADO VLR_ARR
---------- ---------- ---------- ---------- ----------- -----------
        50          1       1,45       10,4 6,971153846        6,87
        50          2       3,91       10,4 18,79807692       18,53
        50          3       5,04       10,4 24,23076923       23,89

SQL&gt;</pre>
<p><strong>PROBLEMA A VISTA!</strong><br />
Quando fazemos rateios e arredondamos o valor, a chance de dar uma diferença de 1 centavo ou mais é muito grande! Se somarmos o valor rateado <em>não fecha com os 49.30</em>!</p>
<p>Veja: 6.87 + 18.53 + 23.89 = 49.29 !!! (diferença de 1 centavo!)</p>
<h3>Resolvendo problema do centavo</h3>
<p>Vamos usar funções analíticas pra jogar essa diferença de 1 centavo para uma das linhas da nota! (no caso, vamos jogar para a linha de maior valor).</p>
<p>Primeiro, vamos descobrir se realmente existe uma diferença de 1 centavo ou mais:</p>
<pre class="brush: sql;">SELECT
  VLR_RATEADO
, ROUND(VLR_RATEADO,2)                        VLR_ARR
, COUNT(1) OVER (ORDER BY 1)                  QTD_LIN
, ROW_NUMBER()    OVER (ORDER BY VLR_RATEADO) LIN
, SUM(VLR_RATEADO) OVER (ORDER BY 1)          SOMA
, SUM(ROUND(VLR_RATEADO,2)) OVER (ORDER BY 1) SOMA_ARR
FROM
(
 SELECT
   nro_nota
 , item
 , valor
 , valor / SUM(valor) OVER (ORDER BY nro_nota) * 49.3 vlr_rateado
 FROM glufke_teste
 WHERE nro_nota = 50
 )
/</pre>
<pre class="brush: plain;">VLR_RATEADO    VLR_ARR    QTD_LIN        LIN       SOMA   SOMA_ARR
----------- ---------- ---------- ---------- ---------- ----------
6,873557692       6,87          3          1       49,3      49,29
18,53490384      18,53          3          2       49,3      49,29
23,89153846      23,89          3          3       49,3      49,29

SQL&gt;</pre>
<p>Acima, as colunas QTD_LIN e LIN vão nos ser úteis pra aplicar a diferença apenas na última linha, ou seja, quando QTD_LIN = LIN (no caso 3=3).<br />
A coluna SOMA, contém o valor total.<br />
A coluna SOMA_ARR é a soma do valor arredondado! Repare que tem 1 centavo a menos!</p>
<p>Então, basta fazer um DECODE que aplica essa diferença (49.3 &#8211; 49.2 &#8211;&gt; SOMA &#8211; SOMA_ARR )<br />
Veja:</p>
<pre class="brush: sql;">SELECT
  VLR_RATEADO
, ROUND(VLR_RATEADO,2) VLR_RATEADO_ARR
, DECODE( COUNT( 1) OVER (ORDER BY 1)
       , ROW_NUMBER()    OVER (ORDER BY VLR_RATEADO)
       , SUM( VLR_RATEADO) OVER (ORDER BY 1) - SUM( ROUND(VLR_RATEADO,2)) OVER (ORDER BY 1)+ ROUND(VLR_RATEADO,2)
       , ROUND(VLR_RATEADO,2)
       )  VLR_COM_DIF
FROM
(
SELECT
  nro_nota
, item
, valor
, (valor) / SUM(valor) OVER (ORDER BY nro_nota) * 49.3 vlr_rateado
FROM GLUFKE_teste
WHERE nro_nota = 50
)
/</pre>
<pre class="brush: plain;">VLR_RATEADO VLR_RATEADO_ARR VLR_COM_DIF
----------- --------------- -----------
6,873557692            6,87        6,87
18,53490384           18,53       18,53
23,89153846           23,89       23,90

SQL&gt;</pre>
<p>O select acima, aplica a diferença de 1 centavo apenas na ultima linha. Dessa forma, a diferença de centavo vai pra uma das linhas e o total rateado sempre fecha corretamente!<br />
A soma do VLR_RATEADO está errada! ( 6,87 + 18,53 + 23,89 = 49,29)<br />
Já o campo VLR_COM_DIF está com a soma correta, fechando os 49,30 !</p>
<p>Dessa forma, com apenas 1 select foi possível realizar o rateio e ainda aplicar a diferença do arredondamento em uma das linhas, graças as funções analíticas!</p>
<h3>Outro Exemplo:</h3>
<pre class="brush: sql;">INSERT INTO glufke_teste VALUES ( 51, 1, 5);
INSERT INTO glufke_teste VALUES ( 51, 2, 5);
INSERT INTO glufke_teste VALUES ( 51, 3, 5);
INSERT INTO glufke_teste VALUES ( 51, 4, 7.5);
INSERT INTO glufke_teste VALUES ( 51, 5, 7.5);</pre>
<p>Vamos aplicar o valor 10 nesses valores:</p>
<pre class="brush: sql;">SELECT
  NRO_NOTA
, ITEM
, VALOR
, ROUND(VLR_RATEADO,2) VLR_RATEADO_ARR
, DECODE( COUNT( 1) OVER (ORDER BY 1)
       , ROW_NUMBER()    OVER (ORDER BY VLR_RATEADO)
       , SUM( VLR_RATEADO) OVER (ORDER BY 1)
       - SUM( ROUND(VLR_RATEADO,2)) OVER (ORDER BY 1)
       + ROUND(VLR_RATEADO,2)
       , ROUND(VLR_RATEADO,2)
       )  VLR_COM_DIF
FROM
(
SELECT
  nro_nota
, item
, valor
, (valor) / SUM(valor) OVER (ORDER BY nro_nota) * 10 vlr_rateado
FROM GLUFKE_teste
WHERE nro_nota = 51
)</pre>
<pre class="brush: plain;">  NRO_NOTA       ITEM      VALOR VLR_RATEADO_ARR VLR_COM_DIF
---------- ---------- ---------- --------------- -----------
        51          1          5            1,67        1,67
        51          2          5            1,67        1,67
        51          3          5            1,67        1,67
        51          4        7,5            2,50        2,50
        51          5        7,5            2,50        2,49     -- &lt; descontou 1 centavo aqui!

SQL&gt;</pre>
<p>Para terminar a saga, vamos adicionar a palavra-chave PARTITION BY, e dessa forma, podemos fazer o calculo acima para todas as notas! No exemplo abaixo, vamos ratear o valor 10 pra cada nota. Ou seja, no total, a soma vai dar 20, pois temos apenas 2 notas no exemplo:</p>
<pre class="brush: sql;">SELECT
  NRO_NOTA
, ITEM
, VALOR
, ROUND(VLR_RATEADO,2) VLR_RATEADO_ARR
, DECODE( COUNT( 1) OVER (partition by nro_nota  ORDER BY 1)
       , ROW_NUMBER()    OVER (partition by nro_nota ORDER BY VLR_RATEADO)
       , SUM( VLR_RATEADO) OVER (partition by nro_nota ORDER BY 1)
       - SUM( ROUND(VLR_RATEADO,2)) OVER (partition by nro_nota ORDER BY 1)
       + ROUND(VLR_RATEADO,2)
       , ROUND(VLR_RATEADO,2)
       )  VLR_COM_DIF
FROM
(
SELECT
  nro_nota
, item
, valor
, (valor) / SUM(valor) OVER (partition by nro_nota ORDER BY nro_nota) * 10 vlr_rateado
FROM GLUFKE_teste
)</pre>
<pre class="brush: plain;">  NRO_NOTA       ITEM      VALOR VLR_RATEADO_ARR VLR_COM_DIF
---------- ---------- ---------- --------------- -----------
        50          1       1,45            1,39        1,39
        50          2       3,91            3,76        3,76
        50          3       5,04            4,85        4,85
        51          1       5,00            1,67        1,67
        51          3       5,00            1,67        1,67
        51          2       5,00            1,67        1,67
        51          5       7,50            2,50        2,50
        51          4       7,50            2,50        2,49

8 rows selected

SQL&gt;</pre>
<p>Observe que a soma da coluna VLR_COM_DIF fecha exatamente os 20. Ja a coluna VLR_RATEADO_ARR dá diferença de centavo!</p>
<p>Neste <a href="https://glufke.net/oracle/download/funcoes_ANALITICAS.html">LINK</a> tem diversos exemplos muito bons! Até mais!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Buscar por INSERT/UPDATE dentro da ALL_SOURCE</title>
		<link>https://glufke.net/2012/02/buscar-por-insertupdate-dentro-da-all_source/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Wed, 15 Feb 2012 19:04:16 +0000</pubDate>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[all_source]]></category>
		<category><![CDATA[fonte]]></category>
		<category><![CDATA[source]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=502</guid>

					<description><![CDATA[É comum termos que procurar qual package ou qual procedure de banco que faz INSERT dentro de uma determinada tabela. Nestes casos, podemos usar a ALL_SOURCE, que contém os códigos de todos programas de banco. Normalmente um select com LIKE resolve o problema: SELECT * FROM all_source WHERE UPPER(text) LIKE '%INSERT%TABELA%' O problema é que [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>É comum termos que procurar qual package ou qual procedure de banco que faz INSERT dentro de uma determinada tabela. </p>
<p>Nestes casos, podemos usar a ALL_SOURCE, que contém os códigos de todos programas de banco. Normalmente um select com LIKE resolve o problema:</p>
<pre class="brush: sql;">SELECT * FROM all_source
WHERE UPPER(text) LIKE '%INSERT%TABELA%'</pre>
<p>O problema é que nem sempre o código está no padrão, por exemplo, o nome da tabela pode estar no lado ou na próxima linha!</p>
<pre class="brush: sql;">INSERT INTO tabelax...

INSERT 
INTO tabelax...
</pre>
<p>O mesmo vale pra UPDATES! Ou seja, se o comando INSERT estiver na linha anterior, essa consulta simples <strong>não vai retornar o que procuramos</strong>!</p>
<pre class="brush: sql;">UPDATE tabelax SET...

UPDATE 
tabelax
SET...
</pre>
<p><span id="more-502"></span></p>
<p>Para resolver o problema, eu fiz esse SQL que busca no banco todas linhas que contém a tabelax E a linha anterior! Com isso você pode encontrar os INSERTS e UPDATES que estão na linha antes também!</p>
<pre class="brush: sql;">SELECT *
FROM (
      SELECT a.owner, a.name, a.line, a.text
      FROM all_source a
      , (
          SELECT owner, name, line, type
          FROM all_source
          WHERE UPPER(text) LIKE '%%ENG_REVISED_ITEMS%'    ----> TABELA A PROCURAR !!!!
            AND owner='APPS'
            AND type <>'PACKAGE'         
         )   B         
      WHERE a.owner = b.owner
        AND a.name  = b.name
        AND a.type  = b.type
        AND (a.line  = b.line or a.line  = b.line-1)
      )
WHERE UPPER(text) LIKE '%INSERT%'                          ----> COMANDO QUE PODE ESTAR NA LINHA ANTERIOR !!!!
ORDER BY 1,2,3,4;</pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Tutorial de Instalação do Oracle APEX 4.1</title>
		<link>https://glufke.net/2011/11/tutorial-de-instalacao-do-oracle-apex-4-1/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Wed, 30 Nov 2011 17:39:42 +0000</pubDate>
				<category><![CDATA[DBA]]></category>
		<category><![CDATA[apex]]></category>
		<category><![CDATA[instalação]]></category>
		<category><![CDATA[xe]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=489</guid>

					<description><![CDATA[Este tutorial mostra como instalar o Apex 4.1 no Oracle XE. Aí vai um passo a passo: 1 – Baixar e instalar Oracle XE Download nesse link: http://www.oracle.com/technetwork/database/express-edition/overview/index.html 2 – Baixar Oracle Apex 4.1 Download nesse link: http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html?ssSourceSiteId=ocombr Descompactar arquivos no C:\oraclexe\apex CMD&#62; cd c:\oraclexe\apex CMD&#62; sqlplus sys@xe as sysdba SQL&#62; @apexins SYSAUX SYSAUX TEMP [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Este tutorial mostra como instalar o Apex 4.1 no Oracle XE. Aí vai um passo a passo:</p>
<h3>1 – Baixar e instalar Oracle XE</h3>
<p>Download nesse link: <a href="http://www.oracle.com/technetwork/database/express-edition/overview/index.html">http://www.oracle.com/technetwork/database/express-edition/overview/index.html</a><br />
<span id="more-489"></span></p>
<h3>2 – Baixar Oracle Apex 4.1</h3>
<p>Download nesse link: <a href="http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html?ssSourceSiteId=ocombr">http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html?ssSourceSiteId=ocombr</a></p>
<p>Descompactar arquivos no C:\oraclexe\apex</p>
<pre class="brush: plain;">CMD&gt; cd c:\oraclexe\apex
CMD&gt; sqlplus sys@xe as sysdba
SQL&gt; @apexins SYSAUX SYSAUX TEMP /i/
CMD&gt; sqlplus sys@xe as sysdba
SQL&gt; @apxldimg.sql c:\oraclexe
SQL&gt; @apxxepwd.sql &lt;password&gt;
SQL&gt; exec dbms_xdb.setListenerLocalAccess (l_access =&gt; FALSE);
SQL&gt; exit
CMD&gt; cd C:\oraclexe\apex\builder\pt-br
CMD&gt; set NLS_LANG=American_America.AL32UTF8
CMD&gt; sqlplus sys@xe as sysdba
SQL&gt; ALTER SESSION SET CURRENT_SCHEMA = APEX_040100;
SQL&gt; @load_pt-br.sql
SQL&gt; exit
CMD&gt; exit</pre>
<h3>3 – Como acessar</h3>
<p>Acesse o Apex pelo navegador: <a href="http://127.0.0.1:8080/apex">http://127.0.0.1:8080/apex</a><br />
<strong> Workspace:</strong> Internal<br />
<strong> Username:</strong> Admin<br />
<strong> Password:</strong> &lt;password&gt;<br />
Agora é só criar sua Workspace e começar a trabalhar..</p>
<p><em>Texto criado por Alex Pagliarini<br />
Comentários <a href="https://glufke.net/oracle/viewtopic.php?f=9&amp;t=8207">aqui</a></em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Impressões sobre o GUOB TECH DAY 2011</title>
		<link>https://glufke.net/2011/08/impressoes-sobre-o-guob-tech-day-2011/</link>
		
		<dc:creator><![CDATA[glufke]]></dc:creator>
		<pubDate>Tue, 16 Aug 2011 16:41:50 +0000</pubDate>
				<category><![CDATA[Evento]]></category>
		<category><![CDATA[2011]]></category>
		<category><![CDATA[GUOB]]></category>
		<category><![CDATA[oracle]]></category>
		<category><![CDATA[sp]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=453</guid>

					<description><![CDATA[Participei do GUOB TECH DAY 2011 e posso dizer: Foi um evento memorável! Resolvi colocar aqui a opinião de algumas pessoas que participaram! Então, aí vai: Aprender Oracle Achei muito bom o evento, muito bem organizado, ótimos palestrantes e congressistas. Valeu cada minuto que estava lá. Parabéns a todos e ano que vem, pretendo ir [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Participei do GUOB TECH DAY 2011 e posso dizer: <strong>Foi um evento memorável!</strong> Resolvi colocar aqui a opinião de algumas pessoas que participaram! Então, aí vai:</p>
<p style="text-align: center;"><img class="aligncenter" src="http://franquini.files.wordpress.com/2011/07/v6_guob_680x320px.jpg?w=614&amp;h=288" alt="GUOB Tech Day" width="476" /></p>
<p><span id="more-453"></span></p>
<blockquote>
<h3>Aprender Oracle</h3>
<p><em>Achei muito bom o evento, muito bem organizado, ótimos palestrantes e congressistas. Valeu cada minuto que estava lá. Parabéns a todos e ano que vem, pretendo ir de novo!!!</em></p>
<p><a href="http://aprenderoracle.com/2011/07/review-do-evento-guob-2011/" target="_blank">http://aprenderoracle.com/2011/07/review-do-evento-guob-2011/</a></p></blockquote>
<p style="text-align: center;"><img loading="lazy" class="aligncenter" src="http://phpdba.files.wordpress.com/2011/07/guob_tech_day_2011_03.jpg" alt="GUOB Tech Day - Palestrantes" width="476" height="318" /></p>
<blockquote>
<h3>PHPDBA</h3>
<p><em>Um evento ótimo, mas sem excelência, seria como ganhar um iPad de presente numa caixa de papelão. Que se dane a caixa de papelão, eu ganhei um iPad!</em></p>
<p><em>O GUOB Tech Day é como ganhar um iPad das mãos do Steve Jobs, tirando uma foto com ele entregando o produto embalado, na caixa original, com uma dedicatória e ainda ganhar um bônus infinito de créditos na AppleStore!</em></p>
<p><em>Eu saio do GUOB com um espírito renovado. Cheio de idéias, cheio de intenções, cheio de vontade de crescer na área, de ser um profissional mais completo, de ajudar a comunidade. Sinto-me muito bem por participar de uma comunidade de DBAs quando estou ali, no meio daquela galera. (Paulo Henrique)</em></p>
<p><a href="http://phpdba.wordpress.com/2011/07/22/guob-tech-day-2011-attendant-feedback/" target="_blank">http://phpdba.wordpress.com/2011/07/22/guob-tech-day-2011-attendant-feedback/</a></p></blockquote>
<p style="text-align: center;"><img loading="lazy" class="aligncenter" src="http://conteudo.imasters.com.br/21478/38546.jpg" alt="GUOB Tech Day" width="476" height="318" /></p>
<blockquote>
<h3>iMasters</h3>
<p><em>O conjunto de palestrantes nacionais e internacionais foi bem escolhido e a organização, instalações, local e demais detalhes foram ótimos. Recomendo a todos que estiverem interessados no mundo de tecnologias Oracle que se filiem gratuitamente ao GUOB e que participem da comunidade para tornar eventos como este cada vez melhores.</em></p>
<p><em></em><br />
<a href="http://www.imasters.com.br/artigo/21478/outros/cobertura-do-guob-tech-day-2011" target="_blank">http://www.imasters.com.br/artigo/21478/outros/cobertura-do-guob-tech-day-2011</a></p></blockquote>
<p style="text-align: center;"><img class="aligncenter" src="http://www.guob.com.br/uploads/images/GUOB2011_fotos/guob_tech_day_2011_100.jpg" alt="GUOB Tech Day" width="476" /></p>
<blockquote>
<h3>Eduardo Legatti</h3>
<p><em>Quem não foi, realmente perdeu uma grande oportunidade de ver excelentes palestras e prestigiar grandes profissionais do mundo Oracle. Foi sensacional.</em></p>
<p><em></em><br />
<a href="http://eduardolegatti.blogspot.com/2011/07/minha-experiencia-no-guob-tech-day-2011.html" target="_blank">http://eduardolegatti.blogspot.com/2011/07/minha-experiencia-no-guob-tech-day-2011.html</a></p></blockquote>
<p style="text-align: center;"><img loading="lazy" class="aligncenter" src="http://aprenderoracle.com/wp-content/uploads/2011/07/IMG_0226.jpg" alt="GUOB Tech Day" width="476" height="318" /></p>
<blockquote>
<h3>CAPIN</h3>
<p><em> Eu Fui! E irei em outros.</em><br />
<a href="http://franquini.wordpress.com/2011/07/17/guob-tech-day-2011/" target="_blank">http://franquini.wordpress.com/2011/07/17/guob-tech-day-2011/</a></p></blockquote>
<div id="ads_336x280"><script type="text/javascript">// <![CDATA[
 google_ad_client = "pub-8964513116661040"; google_alternate_color = "ffffFF"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text_image"; //2007-09-07: wp_quadrado_gra google_ad_channel = "0247072216"; google_color_border = "FFFFFF"; google_color_bg = "FFFFff"; google_color_link = "4F82CB"; google_color_text = "000000"; google_color_url = "4F82CB";
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script></div>
<h3>FOTOS OFICIAIS DO GUOB</h3>
<p><a href="http://www.guob.com.br/index.php?page=album-de-fotos">http://www.guob.com.br/index.php?page=album-de-fotos</a></p>
<h3>COBERTURA PELA OTN LA</h3>
<p>Abaixo, deixo os links da cobertura feita pela OTN:</p>
<p>FOTOS:<br />
<a href="http://flic.kr/s/aHsjvknxN2">Brasil – Oracle Technology Network America Latina Tour 2011</a></p>
<p>VIDEOS:<br />
<a href="http://youtu.be/ht8f9G_NXFI">Rodrigo Almeida</a><br />
<a href="http://youtu.be/0PFRIra2FQU">Eduardo Hahn</a><br />
<a href="http://youtu.be/QpQh7E_MHk8">Marcus Vinicius</a><br />
<a href="http://youtu.be/nImSQinpV8s">Rodrigo Mufalani</a><br />
<a href="http://youtu.be/tIs6BfJXY1k">Thomas Glufke</a><br />
<a href="http://youtu.be/bDChH0FFtw4">David Siquiera</a><br />
<a href="http://youtu.be/uhfvresbVTk">Marina Neumann</a> </p>
<p><em>Se você tem um review do GUOB Tech Day, envie um email para thomas arroba glufke.net com o link do seu review que atualizaremos essa página!</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pipelined Table Functions &#8211; Funções para retornar &#8220;tabelas virtuais&#8221;</title>
		<link>https://glufke.net/2011/07/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/</link>
		
		<dc:creator><![CDATA[fabio_prado]]></dc:creator>
		<pubDate>Thu, 21 Jul 2011 15:42:41 +0000</pubDate>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[pipelined]]></category>
		<category><![CDATA[tabelas]]></category>
		<category><![CDATA[virtuais]]></category>
		<guid isPermaLink="false">http://glufke.net/?p=432</guid>

					<description><![CDATA[Neste artigo irei apresentar um recurso muito bom que existe no Oracle Database desde a versão 9i e chama-se Pipelined Table Function. Este recurso permite criar funções que retornam dados como se fossem uma tabela virtual, podendo transformar os dados de retorno enquanto eles são produzidos, ou seja, é possível alterar os dados pesquisados em [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Neste artigo irei apresentar um recurso muito bom que existe no Oracle Database desde a versão 9i e chama-se <strong>Pipelined Table Function</strong>.</p>
<p>Este recurso permite criar funções que retornam dados como se fossem uma <em>tabela virtual</em>, podendo transformar os dados de retorno enquanto eles são produzidos, ou seja, é possível alterar os dados pesquisados em uma tabela, linha por linha, enquanto eles são processados, sem ter que esperar pelo retorno completo do &#8220;<em>result set</em>&#8221; (conjunto de dados que são retornados pela função).</p>
<p>Este recurso é ótimo para ETL (Extract, Transform, and Load), pois é rápido e consome menos memória que outros métodos que podem ser utilizados para o mesmo objetivo, como por exemplo, preencher um cursor e percorrê-lo para transformar e retornar dados.</p>
<p>Seguem abaixo 3 scripts que demonstram como criar e testar uma <strong>Pipelined Table Function</strong>. Os scripts utilizam a tabela EMPLOYEES do schema de exemplo HR.</p>
<p><em>Para iniciar o passo-a-passo dos itens abaixo, é necessário conectar-se previamente no Banco de Dados desejado, através do SQL Plus, com um usuário com privilégios administrativos (usuário contendo a role DBA ou o privilégio de sistema SYSDBA) ou com o usuário HR.</em></p>
<h3>1- Criando a package HR.PKG_TYPES</h3>
<p>A package <strong>HR.PKG_TYPES</strong> contém os tipos de dados que são criados para retornarem uma tabela virtual na função que será criada no próximo passo:</p>
<pre class="brush: sql;">create or replace package HR.PKG_TYPES as
  TYPE TABLEEMPTYPE IS TABLE OF EMPLOYEES%ROWTYPE;
  TYPE ROWEMPTYPE IS RECORD(
          EMPLOYEE_ID    EMPLOYEES.EMPLOYEE_ID%TYPE,
          FIRST_NAME     EMPLOYEES.FIRST_NAME%TYPE,
          LAST_NAME      EMPLOYEES.LAST_NAME%TYPE,
          EMAIL          EMPLOYEES.EMAIL%TYPE,
          PHONE          EMPLOYEES.PHONE_NUMBER%TYPE,
          HIRE_DATE      EMPLOYEES.HIRE_DATE%TYPE,
          JOB_ID         EMPLOYEES.JOB_ID%TYPE,
          SALARY         EMPLOYEES.SALARY%TYPE,
          COMMISSION_PCT EMPLOYEES.COMMISSION_PCT%TYPE,
          MANAGER_ID     EMPLOYEES.MANAGER_ID%TYPE,
          DEPARTMENT_ID  EMPLOYEES.DEPARTMENT_ID%TYPE
         );
END;
/</pre>
<p><span id="more-432"></span></p>
<div id="ads_336x280"><script type="text/javascript">// <![CDATA[
 google_ad_client = "pub-8964513116661040"; google_alternate_color = "ffffFF"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text_image"; //2007-09-07: wp_quadrado_gra google_ad_channel = "0247072216"; google_color_border = "FFFFFF"; google_color_bg = "FFFFff"; google_color_link = "4F82CB"; google_color_text = "000000"; google_color_url = "4F82CB";
// ]]&gt;</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script></div>
<h3>2- Criando a função HR.FC_OBTER_EMPREGADOS</h3>
<p>A função <strong>HR.FC_OBTER_EMPREGADOS</strong> lê e retorna os dados de apenas 4 colunas da tabela HR.EMPLOYEES, transformando os dados das colunas LAST_NAME e EMAIL:</p>
<pre class="brush: sql;">CREATE OR REPLACE function HR.FC_OBTER_EMPREGADOS
  return PKG_TYPES.TABLEEMPTYPE
  PIPELINED IS
  var_linha PKG_TYPES.ROWEMPTYPE;
BEGIN
  FOR CUR_ROW IN (SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL
                    FROM HR.EMPLOYEES) LOOP
    var_linha.EMPLOYEE_ID := CUR_ROW.EMPLOYEE_ID;
    var_linha.FIRST_NAME  := CUR_ROW.FIRST_NAME;
    var_linha.LAST_NAME   := UPPER(CUR_ROW.LAST_NAME);
    var_linha.EMAIL       := UPPER(cur_row.EMAIL || '@ORACLE.COM');

    PIPE ROW(VAR_LINHA);
  END LOOP;

  RETURN;
END;
/</pre>
<p>Obs.: A instrução PIPE ROW retorna os resultados para a sessão de usuário Oracle, linha por linha. Isso otimiza o tempo de resposta da aplicação.</p>
<h3>3- Testando a função HR.FC_OBTER_EMPREGADOS</h3>
<p>A query abaixo retorna os dados da função <strong>HR.FC_OBTER_EMPREGADOS</strong>, como se fossem uma tabela virtual:</p>
<pre class="brush: sql;">SELECT * FROM TABLE(HR.FC_OBTER_EMPREGADOS);
/</pre>
<h3>Observações:</h3>
<p>O exemplo deste artigo foi criado apenas para demonstrar o uso de Pipelined Table Functions. Para mais informações e exemplos deste tipo de função, consulte as referências no final deste artigo.</p>
<h3>Comentários Finais:</h3>
<p>Apesar das <em>Pipelined Table Functions</em> serem trabalhosas para criar, elas são ótimas para otimizar performance de queries complexas que utilizam funções de transformação para alterar os valores originais das consultas.</p>
<p>Na empresa em que trabalho temos um caso de uma query que demorava <strong>54 segundos</strong> para gerar os dados da folha de ponto mensal de cada empregado. Essa query estava literalmente &#8220;parando&#8221; o servidor de Banco de Dados. Eu orientei o desenvolvedor da query a alterá-la utilizando a <strong>Cláusula WITH </strong>(ver artigo &#8220;Cláusula WITH (para tunar queries)&#8221; que eu postei neste blog em 01/10/2010) <strong>+ Pipelined Table Function</strong>. Após as alterações o tempo de execução da query caiu para <strong>0.4 segundos</strong>.</p>
<h3>Referências:</h3>
<p>&#8211; <a href="http://www.praetoriate.com/10g_139.htm">http://www.praetoriate.com/10g_139.htm</a><br />
&#8211; <a href="http://oraclelon1.oracle.com/docs/cd/B14117_01/appdev.101/b10800/dcitblfnsref.htm">http://oraclelon1.oracle.com/docs/cd/B14117_01/appdev.101/b10800/dcitblfnsref.htm</a><br />
&#8211; <a href="http://www.codeguru.com/cpp/data/mfc_database/oracle/article.php/c4285/">http://www.codeguru.com/cpp/data/mfc_database/oracle/article.php/c4285/</a><br />
&#8211; <a href="http://www.databasejournal.com/features/oracle/article.php/2222781">http://www.databasejournal.com/features/oracle/article.php/2222781</a><br />
&#8211; <a href="http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28425/pipe_paral_tbl.htm#CHDJEGHC">http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28425/pipe_paral_tbl.htm</a></p>
<p><strong>Fonte: <a href="http://www.fabioprado.net/2010/12/pipelined-table-functions-funcao-para.html">http://www.fabioprado.net/2010/12/pipelined-table-functions-funcao-para.html</a></strong></p>
<p><strong><span style="color: #ff0000;">Fábio Prado &#8211; <a href="http://www.fabioprado.net/">http://www.fabioprado.net/</a><br />
Oracle Certified (OCA)<br />
Microsoft Certified (MCT + MCPD + MCAD + MCSD + MCDBA)</p>
<p></span></strong></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
