<?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 &#187; SQL</title>
	<atom:link href="http://glufke.net/category/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://glufke.net</link>
	<description></description>
	<lastBuildDate>Mon, 16 Apr 2012 19:33:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Fazendo Rateio através de Funções Analíticas</title>
		<link>http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/</link>
		<comments>http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 20:43:50 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<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 glufke_teste VALUES ( 50, 3, [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2012%2F04%2F11%2Ffazendo-rateio-atraves-de-funcoes-analiticas%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/"  data-text="Fazendo Rateio através de Funções Analíticas" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p><a href="http://glufke.net/wp-content/uploads/2012/04/rateio.jpg"><img class="size-full wp-image-533 alignright" title="Rateio" src="http://glufke.net/wp-content/uploads/2012/04/rateio.jpg" alt="" width="89" height="90" /></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>
<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>
<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></pre>
<p>Vamos adicionar mais um campo chamado VLR_RATEADO, que arredonda pra 2 casas decimais o valor:</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.3</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></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></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

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> </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="http://glufke.net/oracle/download/funcoes_ANALITICAS.html">LINK</a> tem diversos exemplos muito bons! Até mais!</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2012/04/11/fazendo-rateio-atraves-de-funcoes-analiticas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Buscar por INSERT/UPDATE dentro da ALL_SOURCE</title>
		<link>http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/</link>
		<comments>http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/#comments</comments>
		<pubDate>Wed, 15 Feb 2012 19:04:16 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<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 nem sempre o [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2012%2F02%2F15%2Fbuscar-por-insertupdate-dentro-da-all_source%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/"  data-text="Buscar por INSERT/UPDATE dentro da ALL_SOURCE" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><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>
<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>
<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>
			<wfw:commentRss>http://glufke.net/2012/02/15/buscar-por-insertupdate-dentro-da-all_source/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pipelined Table Functions &#8211; Funções para retornar &#8220;tabelas virtuais&#8221;</title>
		<link>http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/</link>
		<comments>http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/#comments</comments>
		<pubDate>Thu, 21 Jul 2011 15:42:41 +0000</pubDate>
		<dc:creator>fabio_prado</dc:creator>
				<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 uma [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2011%2F07%2F21%2Fpipelined-table-functions-funcoes-para-retornar-tabelas-virtuais%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/"  data-text="Pipelined Table Functions &#8211; Funções para retornar &#8220;tabelas virtuais&#8221;" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><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>- <a href="http://www.praetoriate.com/10g_139.htm">http://www.praetoriate.com/10g_139.htm</a><br />
- <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 />
- <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 />
- <a href="http://www.databasejournal.com/features/oracle/article.php/2222781">http://www.databasejournal.com/features/oracle/article.php/2222781</a><br />
- <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>
			<wfw:commentRss>http://glufke.net/2011/07/21/pipelined-table-functions-funcoes-para-retornar-tabelas-virtuais/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Local Index vs. Global Index em tabela particionada</title>
		<link>http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/</link>
		<comments>http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 12:51:45 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[Oracle 10g]]></category>
		<category><![CDATA[Oracle 11g]]></category>
		<category><![CDATA[Partition]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=207</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			A maioria das pessoas tem essas perguntas sobre Index Partition:

O que é um Local Index?
O que é um Global Index?
Quando você forçaria a criação de um Global Index em uma partition table?
Quando você recomendaria criar um Global Index em vez de um Local Index?

Para responder a essas perguntas&#8230;.
1. O que é um Local Index?
Local Indexes [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2010%2F03%2F31%2Flocal-index-vs-global-indexem-tabela-particionada%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/"  data-text="Local Index vs. Global Index em tabela particionada" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p><img class="alignleft" src="http://www.cs.duke.edu/courses/fall08/cps274/images/gear.jpg" alt="" width="164" height="164" />A maioria das pessoas tem essas perguntas sobre Index Partition:</p>
<ul>
<li><strong>O que é um Local Index?</strong></li>
<li><strong>O que é um Global Index?</strong></li>
<li><strong>Quando você forçaria a criação de um Global Index em uma partition table?</strong></li>
<li><strong>Quando você recomendaria criar um Global Index em vez de um Local Index?</strong></li>
</ul>
<p>Para responder a essas perguntas&#8230;.</p>
<h3>1. O que é um Local Index?</h3>
<p>Local Indexes particionados são mais fáceis de gerenciar, cada partição do Local Index está associado a uma partição. Eles também oferecem maior disponibilidade e são comuns em ambientes de DSS. Quando tomamos qualquer ação (MERGE, SPLIT,EXCHANGE etc) em um Local Index, isso impacta apenas aquela partição e as outras estarão disponíveis. Nós não podemos adicionar explicitamente um Local Index para uma nova partição. O Local Index será adicionado implicitamente a nova partição, quando for criada uma nova partição na tabela. Da mesma forma, não podemos dropar o índice local em uma partição específica. Ele pode ser dropado automaticamente quando nós dropamos a partição da tabela subjacente. Local Indexes podem ser UNIQUE quando a chave da partição é parte do índice composto. Unique Local Indexes são úteis para o ambiente OLTP. Podemos também criar bitmap indexes em tabelas, com a restrição de que os índices de bitmap deve ser local para a tabela particionada. Eles não podem ser Global Indexes.</p>
<pre class="brush: plain;">SQL&gt; CREATE TABLE employees
2 (employee_id NUMBER(4) NOT NULL,
3 last_name VARCHAR2(10),
4 department_id NUMBER(2))
5 PARTITION BY RANGE (department_id)
6 (PARTITION employees_part1 VALUES LESS THAN (10) TABLESPACE ODS_STAGE_DATA,
7 PARTITION employees_part2 VALUES LESS THAN (20) TABLESPACE ODS_STAGE_DATA,
8 PARTITION employees_part3 VALUES LESS THAN (30) TABLESPACE ODS_STAGE_DATA);

Table created.

SQL&gt; declare
2 v_no number :=1;
3 begin
4 delete employees;
5 for i in 1..10 loop
6 insert into employees values(v_no,'name...',v_no);
7 v_no := v_no+1;
8 end loop;
9 end;
10 /

PL/SQL procedure successfully completed.

SQL&gt;
SQL&gt; create index idx_local on employees(last_name) local;

Index created.

SQL&gt;</pre>
<p><span id="more-207"></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. O que é Global Index?</h3>
<p>Global Indexe são usado em ambientes OLTP e oferecem um acesso eficiente a qualquer registro individual. Temos dois tipos de Global Index: Eles são <strong>global Non-partitioned index</strong> e <strong>Global partitioned index</strong>. Global Non-partitioned index se comportam como um índice não particionado.</p>
<p>A chave de partição de um Global partitioned index é independente da chave de partição da tabela. A maior partição de um Global Index deve ter um limite de partição, cujos todos valores são MAXVALUE. Se você quiser adicionar uma nova partição, sempre, é preciso dividir a partição MAX. Se um Global Index Partition está vazio, você pode dropá-lo explicitamente com um ALTER INDEX DROP PARTITION. Se um Global Index Partition contém dados, ao dropar a partição faz com que a partição mais próxima seja marcada como inutilizável. Não é possível dropar a maior partição de um índice global.</p>
<p><strong>Exemplo de  Global Non-partitioned index:</strong></p>
<pre class="brush: plain;">SQL&gt; CREATE INDEX employees_global_idx ON employees(employee_id);

Index created.

SQL&gt;</pre>
<p><strong>Exemplo de Global Partitioned index:</strong></p>
<pre class="brush: plain;">SQL&gt; CREATE INDEX employees_global_part_idx ON employees(employee_id)
2 GLOBAL PARTITION BY RANGE(employee_id)
3 (PARTITION p1 VALUES LESS THAN(3),
4 PARTITION p2 VALUES LESS THAN(6),
5 PARTITION p3 VALUES LESS THAN(9));
PARTITION p3 VALUES LESS THAN(9))
*
ERROR at line 5:
ORA-14021: MAXVALUE must be specified for all columns

SQL&gt; CREATE INDEX employees_global_part_idx ON employees(employee_id)
2 GLOBAL PARTITION BY RANGE(employee_id)
3 (PARTITION p1 VALUES LESS THAN(3),
4 PARTITION p2 VALUES LESS THAN(6),
5 PARTITION p3 VALUES LESS THAN(11),
6 PARTITION p4 VALUES LESS THAN(20),
7 PARTITION p5 VALUES LESS THAN(MAXVALUE));

Index created.</pre>
<p>Agora a partição p4 está vazia. Vamos dropar a partição vazia e ver o status:</p>
<pre class="brush: plain;">SQL&gt; select count(*) from employees where
2 employee_id between 12 and 20;

COUNT(*)
----------
0
SQL&gt; ALTER index employees_global_part_idx drop partition p4;

Index altered.

SQL&gt; SELECT partition_name,status from user_ind_partitions where
2 index_name='EMPLOYEES_GLOBAL_PART_IDX';

PARTITION_NAME STATUS
------------------------------ --------
P1 USABLE
P2 USABLE
P3 USABLE
P5 USABLE</pre>
<p>Agora vamos dropar a partição P3 e ver o estado. Ao dropar essa partição, isso deve invalidar a partição mais próxima. Aqui a partição P5 é a próxima maior partição.</p>
<pre class="brush: plain;">SQL&gt; alter index employees_global_part_idx drop partition p3;

Index altered.

SQL&gt; SELECT partition_name,status from user_ind_partitions where
2 index_name='EMPLOYEES_GLOBAL_PART_IDX';

PARTITION_NAME STATUS
------------------------------ --------
P1 USABLE
P2 USABLE
P5 UNUSABLE

SQL&gt; alter index employees_global_part_idx rebuild;
alter index employees_global_part_idx rebuild
*
ERROR at line 1:
ORA-14086: a partitioned index may not be rebuilt as a whole

SQL&gt; alter index employees_global_part_idx rebuild partition p5;

Index altered.

SQL&gt; SELECT partition_name,status from user_ind_partitions where
2 index_name='EMPLOYEES_GLOBAL_PART_IDX';

PARTITION_NAME STATUS
------------------------------ --------
P1 USABLE
P2 USABLE
P5 USABLE</pre>
<p>Partition Index podem ser mantidos usando UPDATE GLOBAL INDEXES. Os índice estarão disponíveis durante a manutenção e está disponível online. Nós não precisamos de rebuild o índice após a manutenção do índice.</p>
<p>Por exemplo,</p>
<pre class="brush: plain;">SQL&gt; alter table employees drop partition employees_part3
2 update global indexes;

Table altered.

SQL&gt; SELECT partition_name,status from user_ind_partitions where
2 index_name='EMPLOYEES_GLOBAL_PART_IDX';

PARTITION_NAME STATUS
------------------------------ --------
P1 USABLE
P2 USABLE
P5 USABLE

SQL&gt;</pre>
<h3>3. Quando você forçaria a criação de Global index em uma Partition table?</h3>
<p>Quando você cria uma chave primária, você será forçado a criar um Global Index. Quando você cria Unique Index, você é forçado a criar o Global Index. Manter a coluna única é a razão mais comum para os índices globais. Se você tentar criar um Local Index em chave única, você receberá o erro abaixo.</p>
<pre class="brush: plain;">ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index</pre>
<p>Assim, podemos criar Local Index em chave única, quando adicionamos a chave de partição como parte da chave composta no índice. Vamos demonstrar isto:</p>
<p><strong>No exemplo abaixo, o Unique Index falhou já que a chave da partição não é parte da chave composta do índice.</strong></p>
<pre class="brush: plain;">SQL&gt; create unique index idx_emp_id on employees(employee_id) local;
create unique index idx_emp_id on employees(employee_id) local
*
ERROR at line 1:
ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index</pre>
<p>No caso abaixo, ele permite criar um Global Index:</p>
<pre class="brush: plain;">SQL&gt; create unique index idx_emp_id on employees(employee_id);

Index created.

SQL&gt; drop index idx_emp_id;

Index dropped.</pre>
<p>O caso abaixo, o Unique Index é criado com sucesso, pois a chave DEPARTMENT_ID é parte da chave composta.</p>
<pre class="brush: plain;">SQL&gt; create unique index idx_emp_id on employees(employee_id,department_id) local;

Index created.

SQL&gt;</pre>
<h3>4. Quando você recomendaria criar Global Index vs. Local Index?</h3>
<p>Podemos usar Global Index se uma consulta retorna um número pequeno de linhas a partir de um número potencialmente grande de partições.</p>
<p><em>Texto baseado no blog do <a href="http://myorastuff.blogspot.com">Govind</a></em></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2010/03/31/local-index-vs-global-indexem-tabela-particionada/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PLAN_TABLE faz aniversário de 21 anos em 19-out-2009</title>
		<link>http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/</link>
		<comments>http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 17:00:35 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Curiosidade]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=40</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			Pois é isso mesmo! A querida tabela do ORACLE que nos mostra o plano de execução dos SQLs hoje completa 21 anos!
Hoje eu fui olhar um plano de execução e me deparei com a seguinte mensagem:
SET AUTOTRACE ON
SELECT bla bla bla...

Execution Plan
----------------------------------------------------------

--------------------------------------------------------------
&#124; Id  &#124; Operation          [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2009%2F10%2F13%2Fplan_table-faz-aniversario-de-21-anos-em-19-out-2009%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/"  data-text="PLAN_TABLE faz aniversário de 21 anos em 19-out-2009" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>Pois é isso mesmo! A querida tabela do ORACLE que nos mostra o plano de execução dos SQLs hoje completa 21 anos!<br />
Hoje eu fui olhar um plano de execução e me deparei com a seguinte mensagem:</p>
<pre class="brush: plain;">SET AUTOTRACE ON
SELECT bla bla bla...

Execution Plan
----------------------------------------------------------

--------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Cost (%CPU)|
--------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     1 |   102   (0)|
|   1 |  SORT AGGREGATE    |            |     1 |            |
|   2 |   TABLE ACCESS FULL| TABELA     |  4322 |   102   (0)|
--------------------------------------------------------------

Note
-----
   - 'PLAN_TABLE' is old version</pre>
<p>PLAN_TABLE is old version ???<span id="more-40"></span></p>
<div id="ads_336x280"><script type="text/javascript"><!--
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";
//--></script><script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<p>Olhei no script de criação da nova PLAN_TABLE e descobri nos comentários a data de cada modificação: 19 de Outubro de 1988 !</p>
<pre class="brush: plain;">
rem
rem $Header: utlxplan.sql 29-oct-2001.20:28:58 mzait Exp $ xplainpl.sql
rem
Rem Copyright (c) 1988, 2001, Oracle Corporation.  All rights reserved.
Rem NAME
REM    UTLXPLAN.SQL
Rem  FUNCTION
Rem  NOTES
Rem  MODIFIED
Rem     mzait      10/26/01  - add keys and filter predicates to the plan table
Rem     ddas       05/05/00  - increase length of options column
Rem     ddas       04/17/00  - add CPU, I/O cost, temp_space columns
Rem     mzait      02/19/98 -  add distribution method column
Rem     ddas       05/17/96 -  change search_columns to number
Rem     achaudhr   07/23/95 -  PTI: Add columns partition_{start, stop, id}
Rem     glumpkin   08/25/94 -  new optimizer fields
Rem     jcohen     11/05/93 -  merge changes from branch 1.1.710.1 - 9/24
Rem     jcohen     09/24/93 - #163783 add optimizer column
Rem     glumpkin   10/25/92 -  Renamed from XPLAINPL.SQL
Rem     jcohen     05/22/92 - #79645 - set node width to 128 (M_XDBI in gendef)
Rem     rlim       04/29/91 -         change char to varchar2
Rem   Peeler     10/19/88 - Creation
Rem
Rem This is the format for the table that is used by the EXPLAIN PLAN
Rem statement.  The explain statement requires the presence of this
Rem table in order to store the descriptions of the row sources.

create table PLAN_TABLE (
	statement_id 	varchar2(30),
	timestamp    	date,
	remarks      	varchar2(80),
	operation    	varchar2(30),
	options       	varchar2(255),
	object_node  	varchar2(128),
	object_owner 	varchar2(30),
	object_name  	varchar2(30),
	object_instance numeric,
	object_type     varchar2(30),
	optimizer       varchar2(255),
	search_columns  number,
	id		numeric,
	parent_id	numeric,
	position	numeric,
	cost		numeric,
	cardinality	numeric,
	bytes		numeric,
	other_tag       varchar2(255),
	partition_start varchar2(255),
        partition_stop  varchar2(255),
        partition_id    numeric,
	other		long,
	distribution    varchar2(30),
	cpu_cost	numeric,
	io_cost		numeric,
	temp_space	numeric,
        access_predicates varchar2(4000),
        filter_predicates varchar2(4000));
</pre>
<p>Atingiu a maioridade! <img src='http://glufke.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />   Feliz aniversário PLAN_TABLE!</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/10/13/plan_table-faz-aniversario-de-21-anos-em-19-out-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Melhorias nos EXTERNAL TABLES do 10g</title>
		<link>http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/</link>
		<comments>http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 23:48:10 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[External Table]]></category>
		<category><![CDATA[Oracle 10g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=37</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			A partir do Oracle 9i foi criado o conceito de EXTERNAL TABLES, ou seja, você cria uma tabela baseado num arquivo texto no sistema operacional e pode fazer consultas SQL nessa tabela (ou seja, diretamente no arquivo texto como se fosse uma tabela)
Agora a partir do oracle 10g é possível também criar um arquivo texto [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2009%2F01%2F13%2Fmelhorias-nos-external-tables-do-10g%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/"  data-text="Melhorias nos EXTERNAL TABLES do 10g" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>A partir do Oracle 9i foi criado o conceito de EXTERNAL TABLES, ou seja, você cria uma tabela baseado num arquivo texto no sistema operacional e pode fazer consultas SQL nessa tabela (ou seja, diretamente no arquivo texto como se fosse uma tabela)<br />
Agora a partir do oracle 10g é possível também criar um arquivo texto baseado numa tabela do banco usando o novo driver de Data Pump existente.<span id="more-37"></span> </p>
<p>A possibilidade de gravar um arquivo texto se limita ao CREATE TABLE AS SELECT apenas. Não é permitido fazer UPDATE, DELETE ou INSERT numa external table.</p>
<p>Vamos a um exemplo:</p>
<pre class="brush: sql;">SQL> CREATE DIRECTORY external_directory AS
'c:\oracle\admin\betatwo\directory';

SQL> GRANT READ, WRITE ON DIRECTORY external_directory
TO scott;
SQL> CREATE TABLE emp_history_ext
(ename, retire_date,
last_retirement_pay_date, pay_amount)
ORGANIZATION EXTERNAL
( TYPE oracle_datapump
  DEFAULT DIRECTORY external_directory
LOCATION ('emp_history_01.exp', 'emp_history_02.exp') )
parallel
AS
SELECT a.ename, b.retire_date,
b.last_retirement_pay_date, b.pay_amount
FROM emp a, retire_pay b
WHERE a.empno=b.empno;</pre>
<p>Primeiramente, criamos um DIRECTORY e damos permissão de leitura e escrita. Isso apenas é requerido caso o usuário que criou o diretório não é o usuário que vai criar a external table. Após isso, criamos uma external table que será populada com o SELECT informado!</p>
<div id="ads_336x280"><script type="text/javascript"><!--
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";
//--></script><script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<p>Após a criação, basta fazer a consulta diretamente no arquivo texto:</p>
<pre class="brush: sql;">SQL> SELECT * FROM emp_history_ext;

ENAME      RETIRE_DA LAST_RETI PAY_AMOUNT
---------- --------- --------- ----------
SMITH      25-NOV-03 15-DEC-03       1000</pre>
<p>A criação dessa external table resulta na criação de um arquivo texto no sistema operacional com os dados informados no SELECT. Também é gerado um arquivo de LOG no mesmo diretório:</p>
<pre class="brush: plain;">C:\> dir c:\oracle\admin\betatwo\directory
 Volume in drive C has no label.
 Volume Serial Number is 3CE9-7321
 Directory of c:\oracle\admin\betatwo\directory
12/15/2003 07:52  PM      90    EMP_HISTORY_EXT_2528_1760.log
12/15/2003 07:52  PM   1,808    emp_history.exp</pre>
<p>Outras informações:<br />
Quando você dropa uma external table os arquivos textos continuam no sistema operacional! Isso pode ser um problema pois caso você execute novamente o comando pra recriar a external table, os arquivos já existirão e ocasionará um ERRO. Você deve excluir esses arquivos manualmente.</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/01/13/melhorias-nos-external-tables-do-10g/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Novas funcionalidades com CONNECT BY</title>
		<link>http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/</link>
		<comments>http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 11:23:42 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Connect By]]></category>
		<category><![CDATA[Oracle 10g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=38</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			A partir do Oracle 10g temos mais algumas funcionalidades no uso da cláusula CONNECT BY dentro dos comandos SELECT. Essas mudanças se aplicam a queries hiearquicas permitindo o retorno de não apenas PAIS, FILHOS mas também &#8220;ancestrais&#8221;. São 3 as novas cláusulas disponíveis com CONNECT BY. 



connect_by_iscycle
Determina se a linha corrente tem uma linha filha [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2009%2F01%2F12%2Fnovas-funcionalidades-com-connect-by%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/"  data-text="Novas funcionalidades com CONNECT BY" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>A partir do Oracle 10g temos mais algumas funcionalidades no uso da cláusula CONNECT BY dentro dos comandos SELECT. Essas mudanças se aplicam a queries hiearquicas permitindo o retorno de não apenas PAIS, FILHOS mas também &#8220;ancestrais&#8221;. São 3 as novas cláusulas disponíveis com CONNECT BY.<span id="more-38"></span> </p>
<div id="ads_336x280"><script type="text/javascript"><!--
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";
//-->
</script><script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<p><strong>connect_by_iscycle</strong><br />
Determina se a linha corrente tem uma linha filha que também é seu ancestral.</p>
<pre class="brush: sql;">SQL>  SELECT ename Emp, CONNECT_BY_ISCYCLE leaf, mgr "Manager",
  2     LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(empno, '/') "Path"
  3     FROM emp
  4     Where level-1 < 3
  5     CONNECT BY NOCYCLE PRIOR empno = mgr;

EMP              LEAF Manager    Pathlen Path
---------- ---------- ------- ---------- ------------------------------
SCOTT               0    7566          0 /7788
ADAMS               0    7788          1 /7788/7876
FORD                0    7566          0 /7902
SMITH               0    7902          1 /7902/7369
ALLEN               0    7698          0 /7499
WARD                0    7698          0 /7521
MARTIN              0    7698          0 /7654
TURNER              0    7698          0 /7844
JAMES               0    7698          0 /7900
MILLER              0    7782          0 /7934
ADAMS               0    7788          0 /7876
JONES               0    7839          0 /7566
SCOTT               0    7566          1 /7566/7788
ADAMS               0    7788          2 /7566/7788/7876
FORD                0    7566          1 /7566/7902
SMITH               0    7902          2 /7566/7902/7369
BLAKE               0    7839          0 /7698
ALLEN               0    7698          1 /7698/7499
WARD                0    7698          1 /7698/7521
MARTIN              0    7698          1 /7698/7654
TURNER              0    7698          1 /7698/7844
JAMES               0    7698          1 /7698/7900
CLARK               0    7839          0 /7782
MILLER              0    7782          1 /7782/7934
SMITH               0    7902          0 /7369
KING                0                  0 /7839
JONES               0    7839          1 /7839/7566
SCOTT               0    7566          2 /7839/7566/7788
FORD                0    7566          2 /7839/7566/7902
BLAKE               0    7839          1 /7839/7698
ALLEN               0    7698          2 /7839/7698/7499
WARD                0    7698          2 /7839/7698/7521
MARTIN              0    7698          2 /7839/7698/7654
TURNER              0    7698          2 /7839/7698/7844
JAMES               0    7698          2 /7839/7698/7900
CLARK               0    7839          1 /7839/7782
MILLER              0    7782          2 /7839/7782/7934

37 rows selected

SQL> </pre>
<p><strong>connect_by_isleaf</strong><br />
Determina se a linha corrente é uma FOLHA na árvore definida pela operação connect by.</p>
<pre class="brush: sql;">SQL> SELECT ename "Emp", CONNECT_BY_ISLEAF leaf, mgr "Manager",
  2     LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(empno, '/') "Path"
  3     FROM emp
  4     Where level-1 < 3
  5     CONNECT BY NOCYCLE PRIOR empno = mgr;

Emp              LEAF Manager    Pathlen Path
---------- ---------- ------- ---------- ------------------------------
SCOTT               0    7566          0 /7788
ADAMS               1    7788          1 /7788/7876
FORD                0    7566          0 /7902
SMITH               1    7902          1 /7902/7369
ALLEN               1    7698          0 /7499
WARD                1    7698          0 /7521
MARTIN              1    7698          0 /7654
TURNER              1    7698          0 /7844
JAMES               1    7698          0 /7900
MILLER              1    7782          0 /7934
ADAMS               1    7788          0 /7876
JONES               0    7839          0 /7566
SCOTT               0    7566          1 /7566/7788
ADAMS               1    7788          2 /7566/7788/7876
FORD                0    7566          1 /7566/7902
SMITH               1    7902          2 /7566/7902/7369
BLAKE               0    7839          0 /7698
ALLEN               1    7698          1 /7698/7499
WARD                1    7698          1 /7698/7521
MARTIN              1    7698          1 /7698/7654
TURNER              1    7698          1 /7698/7844
JAMES               1    7698          1 /7698/7900
CLARK               0    7839          0 /7782
MILLER              1    7782          1 /7782/7934
SMITH               1    7902          0 /7369
KING                0                  0 /7839
JONES               0    7839          1 /7839/7566
SCOTT               0    7566          2 /7839/7566/7788
FORD                0    7566          2 /7839/7566/7902
BLAKE               0    7839          1 /7839/7698
ALLEN               1    7698          2 /7839/7698/7499
WARD                1    7698          2 /7839/7698/7521
MARTIN              1    7698          2 /7839/7698/7654
TURNER              1    7698          2 /7839/7698/7844
JAMES               1    7698          2 /7839/7698/7900
CLARK               0    7839          1 /7839/7782
MILLER              1    7782          2 /7839/7782/7934

37 rows selected

SQL> </pre>
<p><strong>connect_by_root</strong><br />
Retorna o valor da coluna da linha Raíz.</p>
<pre class="brush: sql;">SQL> SELECT ename "Emp", CONNECT_BY_ROOT mgr "Manager",
  2     LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(empno, '/') "Path"
  3     FROM emp
  4     Where level-1 < 3
  5     CONNECT BY NOCYCLE PRIOR empno = mgr;

Emp           Manager    Pathlen Path
---------- ---------- ---------- ------------------------------
SCOTT            7566          0 /7788
ADAMS            7566          1 /7788/7876
FORD             7566          0 /7902
SMITH            7566          1 /7902/7369
ALLEN            7698          0 /7499
WARD             7698          0 /7521
MARTIN           7698          0 /7654
TURNER           7698          0 /7844
JAMES            7698          0 /7900
MILLER           7782          0 /7934
ADAMS            7788          0 /7876
JONES            7839          0 /7566
SCOTT            7839          1 /7566/7788
ADAMS            7839          2 /7566/7788/7876
FORD             7839          1 /7566/7902
SMITH            7839          2 /7566/7902/7369
BLAKE            7839          0 /7698
ALLEN            7839          1 /7698/7499
WARD             7839          1 /7698/7521
MARTIN           7839          1 /7698/7654
TURNER           7839          1 /7698/7844
JAMES            7839          1 /7698/7900
CLARK            7839          0 /7782
MILLER           7839          1 /7782/7934
SMITH            7902          0 /7369
KING                           0 /7839
JONES                          1 /7839/7566
SCOTT                          2 /7839/7566/7788
FORD                           2 /7839/7566/7902
BLAKE                          1 /7839/7698
ALLEN                          2 /7839/7698/7499
WARD                           2 /7839/7698/7521
MARTIN                         2 /7839/7698/7654
TURNER                         2 /7839/7698/7844
JAMES                          2 /7839/7698/7900
CLARK                          1 /7839/7782
MILLER                         2 /7839/7782/7934

37 rows selected

SQL> </pre>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/01/12/novas-funcionalidades-com-connect-by/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cláusula RETURNING com funções somatórias</title>
		<link>http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/</link>
		<comments>http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/#comments</comments>
		<pubDate>Fri, 09 Jan 2009 12:57:54 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Oracle 10g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=39</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			Oracle 10g agora permite o uso de funções somatórias na cláusula RETURNING. O seguinte exemplo faz um UPDATE no salário de todos empregados e retorna a média salarial resultante para as linhas afetadas. 
SQL> VARIABLE a NUMBER
SQL> UPDATE employee
  2  SET sal=sal*1.10 RETURNING AVG(sal) INTO :a;
SQL> PRINT a
      [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2009%2F01%2F09%2Fclausula-returning-com-funcoes-somatorias%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/"  data-text="Cláusula RETURNING com funções somatórias" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>Oracle 10g agora permite o uso de funções somatórias na cláusula RETURNING. O seguinte exemplo faz um UPDATE no salário de todos empregados e retorna a média salarial resultante para as linhas afetadas.<span id="more-39"></span> </p>
<pre class="brush: sql;">SQL> VARIABLE a NUMBER
SQL> UPDATE employee
  2  SET sal=sal*1.10 RETURNING AVG(sal) INTO :a;
SQL> PRINT a
           a
    --------
      655.22</pre>
<div id="ads_336x280"><script type="text/javascript"><!--
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";
//-->
</script><script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<p>O mesmo exemplo acima mostrado dentro de um bloco PL/SQL:</p>
<pre class="brush: sql;">Declare
     a   number;
begin
     update employee set sal=sal*1.10 returning avg(sal) into a;
     dbms_output.put_line(a);
end;</pre>
<p>Lembre-se que essa média é apenas das linhas afetadas pelo UPDATE!</p>
<p>Também é possível utilizar em comandos DELETE:</p>
<pre class="brush: sql;">Declare
     a   number;
begin
     delete from employee where sal > 1000 returning avg(sal) into a;
     dbms_output.put_line(a);
end;</pre>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/01/09/clausula-returning-com-funcoes-somatorias/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ignorando Acentos e Maiúsculas/Minúsculas no 10g</title>
		<link>http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/</link>
		<comments>http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/#comments</comments>
		<pubDate>Thu, 08 Jan 2009 12:19:12 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Acentuação]]></category>
		<category><![CDATA[Oracle 10g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=36</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			O Oracle 10g agora permite fazer consultas considerando ou não acentos e maiúsculas/minúsculas. Isso é feito pelo uso do parâmetro NLS_SORT. Vamos aos exemplos.
Temos que adicionar o prefixo _ai para &#8220;accent insensitive&#8221; (ignora os acentos). Ou _ci para &#8220;case insensitive&#8221; (ignora se é maiúsculo ou minúsculo).
O nls_sort afeta uma série de funções SQL e operações, [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2009%2F01%2F08%2Fignorando-acentos-e-maiusculasminusculas-no-10g%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/"  data-text="Ignorando Acentos e Maiúsculas/Minúsculas no 10g" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>O Oracle 10g agora permite fazer consultas considerando ou não acentos e maiúsculas/minúsculas. Isso é feito pelo uso do parâmetro <strong>NLS_SORT</strong>. Vamos aos exemplos.<span id="more-36"></span></p>
<p>Temos que adicionar o prefixo <strong>_ai</strong> para &#8220;accent insensitive&#8221; (ignora os acentos). Ou <strong>_ci</strong> para &#8220;case insensitive&#8221; (ignora se é maiúsculo ou minúsculo).</p>
<p>O nls_sort afeta uma série de funções SQL e operações, incluindo essas:<br />
* WHERE<br />
* ORDER BY<br />
* START WITH<br />
* HAVING<br />
* IN / NOT IN<br />
* BETWEEN<br />
* CASE-WHEN</p>
<p>Algumas funções entretanto, não são afetadas pelo nls_sort. (Como LIKE, TRIM, INSTR).</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>
<p>Observe o comportamento normal do ORDER BY:</p>
<pre class="brush: sql;">SQL&gt; select * from thomas_teste order by 1;

NOME
-------------------------------------------
THOMAS 2
Thomas 3
thomas 1

SQL&gt; </pre>
<p>Agora, a mesma consulta, mas antes mudamos o NLS_SORT para ignorar os maiúsculos e minúsculos:</p>
<pre class="brush: sql;">SQL&gt; ALTER SESSION SET NLS_SORT=generic_m_ci;

Session altered.

SQL&gt; select * from thomas_teste order by 1;

NOME
-----------------------------------------------
thomas 1
THOMAS 2
Thomas 3

SQL&gt; </pre>
<p>Agora, o mesmo resultado acima SEM mudar a sessão:</p>
<pre class="brush: sql;">SQL&gt; select * from thomas_teste
2  order by nlssort( nome, 'NLS_SORT=generic_m_ci');

NOME
-------------------------------------------------------
thomas 1
THOMAS 2
Thomas 3

SQL&gt; </pre>
<p>E é claro, também pode usar o <strong>_ai</strong> para ignorar os acentos.<br />
NOTA: o <strong>_ai</strong> inclui a funcionalidade do CASE INSENSITIVE também!</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/01/08/ignorando-acentos-e-maiusculasminusculas-no-10g/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Select que retorna os Números Primos</title>
		<link>http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/</link>
		<comments>http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/#comments</comments>
		<pubDate>Thu, 11 Oct 2007 22:40:31 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Curiosidade]]></category>
		<category><![CDATA[Matemática]]></category>

		<guid isPermaLink="false">http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/</guid>
		<description><![CDATA[
			
			
			
			
			
			
			
						
			Esse post vai mais a título de curiosidade. Sabemos que os números primos são números naturais que podem ser divididos apenas por dois números naturais, o 1 (um) e ele mesmo. Pois a tempos que eu queria um SQL que retornasse esses números! 
Após um pouco de tentativas, saiu o SQL abaixo:
select z.zz PRIMOS
from
 (select [...]]]></description>
			<content:encoded><![CDATA[<div class="bottomcontainerBox" style="">
			<div style="float:left; width:50px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fglufke.net%2F2007%2F10%2F11%2Fselect-que-retorna-os-numeros-primos%2F&amp;layout=button_count&amp;show_faces=false&amp;width=50&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:50px; height:21px;"></iframe></div>
			<div style="float:left; width:60px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/"></g:plusone>
			</div>
			<div style="float:left; width:70px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/"  data-text="Select que retorna os Números Primos" data-count="horizontal" data-via="glufke"></a>
			</div><div style="float:left; width:110px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script type="in/share" data-url="http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/" data-counter="right"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div><p>Esse post vai mais a título de curiosidade. Sabemos que os <a href="http://pt.wikipedia.org/wiki/N%C3%BAmero_primo">números primos</a> são números naturais que podem ser divididos apenas por dois números naturais, o 1 (um) e ele mesmo. Pois a tempos que eu queria um SQL que retornasse esses números! <span id="more-20"></span></p>
<p>Após um pouco de tentativas, saiu o SQL abaixo:</p>
<pre class="brush: sql;">select z.zz PRIMOS
from
 (select rownum+1 zz
  from user_tables
  where rownum < 100
 ) z
where zz not in (
                select y.bb
                from (select rownum+1 aa from user_tables a where rownum < 100) x
                ,    (select rownum+1 bb from user_tables b where rownum < 100) y
                where bb<>aa
                  and mod(bb, aa)=0
                  and aa<=bb
                )
/</pre>
<div id="ads_336x280"><script type="text/javascript"><!--
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";
//-->
</script><script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<p>Abaixo, colocaremos uma amostra dos resultados:</p>
<pre class="brush: sql;">SQL> select z.zz PRIMOS
  2  from
  3   (select rownum+1 zz
  4    from user_tables
  5    where rownum < 100
  6   ) z
  7  where zz not in (
  8                  select y.bb
  9                  from (select rownum+1 aa from user_tables a where rownum < 100) x
 10                  ,    (select rownum+1 bb from user_tables b where rownum < 100) y
 11                  where bb<>aa
 12                    and mod(bb, aa)=0
 13                    and aa<=bb
 14                  )
 15  /

   PRIMOS
---------
        2
        3
        5
        7
       11
       13
       17
       19
       23
       29
       31
       37
       41
       43
       47
       53
       59
       61
       67
       71
       73
       79
       83
       89
       97

25 rows selected.
SQL></pre>
<p>Talvez essa não seja a melhor forma de fazer isso (obviamente, que usar SQL pra calcular isso não é a melhor saída). Mesmo assim, fica como um "desafio vencido". </p>
<p>Comentários <a href="http://glufke.net/oracle/viewtopic.php?t=637">aqui</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2007/10/11/select-que-retorna-os-numeros-primos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

