<?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; PL/SQL</title>
	<atom:link href="http://glufke.net/tag/plsql/feed/" rel="self" type="application/rss+xml" />
	<link>http://glufke.net</link>
	<description></description>
	<lastBuildDate>Wed, 30 Nov 2011 17:41:41 +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>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[<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>Converter datas do Excel para Oracle</title>
		<link>http://glufke.net/2009/12/08/converter-datas-do-excel-para-oracle/</link>
		<comments>http://glufke.net/2009/12/08/converter-datas-do-excel-para-oracle/#comments</comments>
		<pubDate>Tue, 08 Dec 2009 18:04:29 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[Datas]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Funções]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=177</guid>
		<description><![CDATA[MS Excel usa um formato de data chamado &#8220;Serial Date format&#8221; ao armazenar e lidar com datas e horas. A &#8220;Data serial&#8221; é calculada pegando o número de dias entre uma data qualquer e o dia 01/01/1900.
Por que isso é importante para um desenvoledor Oracle ? Se você está criando um documento em PL/SQL que [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://glufke.net/upload/upload_files/excel_oracle.JPG" title="excel_oracle" class="alignleft" width="134" height="135"  />MS Excel usa um formato de data chamado &#8220;Serial Date format&#8221; ao armazenar e lidar com datas e horas. A &#8220;Data serial&#8221; é calculada pegando o número de dias entre uma data qualquer e o dia 01/01/1900.</p>
<p>Por que isso é importante para um desenvoledor Oracle ? Se você está criando um documento em PL/SQL que será aberto no Excel, a data ficará incorreta a não ser que você converta antes para o padrão do Excel.</p>
<p>Felizmente, a formula de conversão de datas é muito simples. A seguinte função fará a conversão de uma data no Oracle para o padrão do Excel:</p>
<pre class="brush: sql;">CREATE OR REPLACE FUNCTION convertOracleToSerialDate(p_date DATE) RETURN NUMBER
IS
BEGIN
RETURN (p_date – TO_DATE(’01-JAN-1900?))+2;
END;
/</pre>
<p><span id="more-177"></span>
<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>Veja:</p>
<pre class="brush: plain;">SQL*Plus: Release 10.2.0.4.0 – Production on Mon Nov 23 22:31:54 2009

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Express Edition Release 10.2.0.1.0 – Production

SQL> select convertOracleToSerialDate(’05-MAY-1968?) from dual;

CONVERTORACLETOSERIALDATE(’05-MAY-1968?)
—————————————-
24963</pre>
<p>Se passarmos o valor &#8220;05-MAY-1968&#8243; para a função acima, teremos como resopsta 24963. Agora, se colocarmos esse valor numa planilha excel e mudar o tipo da celula para DATA, teremos esse número convertido para &#8220;05/05/1968&#8243;, ou qualquer outro formato que você escolher.</p>
<p>O reverso também é possível. Caso desejamos converter do formato excel para oracle, usamos essa simples função:</p>
<pre class="brush: sql;">CREATE OR REPLACE FUNCTION convertSerialToOracleDate(p_serial_date NUMBER) RETURN DATE
IS
BEGIN
  RETURN (TO_DATE(’01-JAN-1900?) + p_serial_date)-2;
END;
/</pre>
<p>Exemplo:</p>
<pre class="brush: plain;">SQL*Plus: Release 10.2.0.4.0 – Production on Mon Nov 23 22:45:44 2009

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Express Edition Release 10.2.0.1.0 – Production

SQL> select convertSerialToOracleDate(24963) from dual;

CONVERTSE
———
05-MAY-68

SQL></pre>
<p><em>Agradecimentos a Jason Bennett pelas dicas acima.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/12/08/converter-datas-do-excel-para-oracle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Colunas Virtuais no 11g &#8211; Parte 2</title>
		<link>http://glufke.net/2009/08/17/colunas-virtuais-no-11g-parte-2/</link>
		<comments>http://glufke.net/2009/08/17/colunas-virtuais-no-11g-parte-2/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 02:43:22 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[Coluna Virtual]]></category>
		<category><![CDATA[Oracle 11g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=101</guid>
		<description><![CDATA[Colunas Virtuais no 11g &#8211; Parte 2 &#8211; Índices e Constraints
Continuando o artigo sobre colunas virtuais no Oracle 11g, veremos outras possibilidades do uso dessa feature.
Se tentarmos inserir dados que resultem em uma coluna virtual duplicada, podemos esperar uma violação de Unique Constraint:
SQL> INSERT INTO t (n1, n2) VALUES (10, 20);
INSERT INTO t (n1, n2) [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Colunas Virtuais no 11g &#8211; Parte 2 &#8211; Índices e Constraints</strong></p>
<p>Continuando o artigo sobre colunas virtuais no Oracle 11g, veremos outras possibilidades do uso dessa feature.</p>
<p>Se tentarmos inserir dados que resultem em uma coluna virtual duplicada, podemos esperar uma violação de Unique Constraint:<span id="more-101"></span></p>
<pre class="brush: sql;">SQL> INSERT INTO t (n1, n2) VALUES (10, 20);
INSERT INTO t (n1, n2) VALUES (10, 20)
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.T_PK) violated</pre>
<p>Como vimos, gerou o exception ORA-00001.</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>Em seguida, veremos que, como podemos criar uma chave primária em uma coluna virtual, também podemos referenciá-la a uma constraint Foreign Key. No próximo exemplo, vamos criar uma tabela filha com uma foreign key para a coluna virtual N3.</p>
<pre class="brush: sql;">SQL> CREATE TABLE t_child
  2  ( n3 INT
  3  , CONSTRAINT tc_fk
  4       FOREIGN KEY  (n3)
  5       REFERENCES  t(n3)
  6  );

Table created.</pre>
<p>Iremos agora inserir alguns valores válidos e inválidos:</p>
<pre class="brush: sql;">SQL> INSERT INTO t_child VALUES (30);

1 row created.

SQL> INSERT INTO t_child VALUES (40);
INSERT INTO t_child VALUES (40)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.TC_FK) violated - parent key not found</pre>
<p><a href="http://glufke.net/2009/07/31/colunas-virtuais-no-oracle-11g/">Colunas Virtuais no 11g &#8211; Parte 1 &#8211; Introdução</a><br />
Colunas Virtuais no 11g &#8211; Parte 2 &#8211; Índices e Constraints</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/08/17/colunas-virtuais-no-11g-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Colunas Virtuais no 11g &#8211; Parte 1</title>
		<link>http://glufke.net/2009/07/31/colunas-virtuais-no-oracle-11g/</link>
		<comments>http://glufke.net/2009/07/31/colunas-virtuais-no-oracle-11g/#comments</comments>
		<pubDate>Fri, 31 Jul 2009 19:54:06 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[Coluna Virtual]]></category>
		<category><![CDATA[Oracle 11g]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=99</guid>
		<description><![CDATA[Oracle suportou expressões armazenadas por muitos anos, em views e índices baseados em função. Mais principalmente, são as views que nos permitem armazenar e modularisar expressões calculadas baseados em outras colunas da tabela. 
Em versões mais recentes (a partir do 8i), temos como indexar as colunas baseados em função. (Function based indexes). Agora, a partir [...]]]></description>
			<content:encoded><![CDATA[<p>Oracle suportou expressões armazenadas por muitos anos, em views e índices baseados em função. Mais principalmente, são as views que nos permitem armazenar e modularisar expressões calculadas baseados em outras colunas da tabela. </p>
<p>Em versões mais recentes (a partir do 8i), temos como indexar as colunas baseados em função. (Function based indexes). Agora, a partir da versão 11g, o banco Oracle nos permite também armazenar expressões diretamente nas tabelas como colunas virtuais.</p>
<p>Como veremos neste artigo, colunas virtuais são mais flexíveis que as outras alternativas citadas. Vamos examinar seu uso básico e também considerar alguns outros aspectos dessa nova feature.<span id="more-99"></span></p>
<p><strong>CRIANDO UMA COLUNA VIRTUAL</strong></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>Começaremos criando uma simples tabela com uma única coluna virtual</p>
<pre class="brush: sql;">SQL> CREATE TABLE t
  2  ( n1 INT
  3  , n2 INT
  4  , n3 INT GENERATED ALWAYS AS (n1 + n2) VIRTUAL
  5  );

Table created.</pre>
<p>Vemos que uma coluna virtual é gerada de uma simples expressão envolvendo as outras colunas da tabela. A palavra chave VIRTUAL é opcional. Foi incluída pelo que a Oracle chama da &#8220;Clareza sintática&#8221;.</p>
<p>Colunas virutais não são armazenadas em disco. Elas são geradas em tempo de execução usando as expressões associadas (em nosso exemplo, N1 + N2). Existe algumas implicações na forma de inserir dados em tabelas que usam colunas virtuais:</p>
<pre class="brush: sql;">SQL> INSERT INTO t VALUES (10, 20, 30);
INSERT INTO t VALUES (10, 20, 30)
            *
ERROR at line 1:
ORA-54013: INSERT operation disallowed on virtual columns</pre>
<p>Outra forma que não pode ser feita:</p>
<pre class="brush: sql;">SQL> INSERT INTO t VALUES (10, 20);
INSERT INTO t VALUES (10, 20)
            *
ERROR at line 1:
ORA-00947: not enough values</pre>
<p>Tirando o fato que não podemos inserir ou alterar as colunas virtuais, elas ainda assim são consideradas parte da lista de colunas. Isso significa portanto, que precisamos referenciar as colunas físicas explicitamente nos comandos INSERT, como abaixo:</p>
<pre class="brush: sql;">SQL> INSERT INTO t (n1, n2) VALUES (10, 20);

1 row created.</pre>
<p>É claro que a prática acima já faz parte das melhores práticas que todo dsenevolvedor deve ter. Agora que temos dados dentro do nosso exemplo, podemos consultar a coluna virtual:</p>
<pre class="brush: sql;">SQL> SELECT * FROM t;

        N1         N2         N3
---------- ---------- ----------
        10         20         30

1 row selected.</pre>
<p>Nossa expressão é montada em tempo de execução e nos dá a saída acima!</p>
<p>Colunas Virtuais no 11g &#8211; Parte 1 &#8211; Introdução<br />
<a href="http://glufke.net/2009/08/17/colunas-virtuais-no-11g-parte-2/">Colunas Virtuais no 11g &#8211; Parte 2 &#8211; Índices e Constraints</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/07/31/colunas-virtuais-no-oracle-11g/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trabalhando com Strings no Oracle</title>
		<link>http://glufke.net/2009/06/03/trabalhando-com-strings-no-oracle/</link>
		<comments>http://glufke.net/2009/06/03/trabalhando-com-strings-no-oracle/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 01:36:11 +0000</pubDate>
		<dc:creator>Rodrigo Valentim</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[String]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=96</guid>
		<description><![CDATA[Vou agora tentar mostrar como trabalha com string no Oracle&#8230; Venho acompanhando alguns Foruns de Desenvolvimento e sempre estou me deparando com questões sobre o correto uso de funções para trabalhar com String&#8230; 

Concatenando 2 Strings
Colocando a primeira letra do texto como Maiúscula
Transformando o texto em texto Minúsculo e Maiúsculo
Convertendo letras em códigos ASCII
Localizando a [...]]]></description>
			<content:encoded><![CDATA[<p>Vou agora tentar mostrar como trabalha com string no Oracle&#8230; Venho acompanhando alguns Foruns de Desenvolvimento e sempre estou me deparando com questões sobre o correto uso de funções para trabalhar com String&#8230; </p>
<ol>
<li>Concatenando 2 Strings</li>
<li>Colocando a primeira letra do texto como Maiúscula</li>
<li>Transformando o texto em texto Minúsculo e Maiúsculo</li>
<li>Convertendo letras em códigos ASCII</li>
<li>Localizando a posição uma string no meio do texto</li>
<li>Atribuindo dígitos no final e/ou no inicio do texto</li>
<li>Removendo espaços no inicio e/ou fim do texto</li>
<li>Como inverter o texto</li>
<li>Substituindo Strings por outras Strings</li>
<li>Cortando o conteúdo do texto</li>
<li>Descobrindo o tamanho da string</li>
<li>Retornando colunas com valor não nulo</li>
<li>Exemplo da utilização de algumas funções
<ul>
<li>Pesquisando em uma string por um digito e exibindo o resto da string pegando como base esse digito localizado.</li>
<li>Repartindo uma string e inserindo um valor no meio.</li>
</ul>
</li>
</ol>
<p><span id="more-96"></span>
<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>1. Concatenando 2 strings</strong></p>
<p>Existem duas formas de trabalhar concatenando strings.  CONCAT e PIPE<br />
Concat: </p>
<pre class="brush: sql;">SQL: SELECT CONCAT ('Rodrigo ', 'Valentim') FROM dual;
CONCAT('RODRIGO','VALENTIM')
----------------------------
Rodrigo Valentim
</pre>
<p>Usando PIPE: </p>
<pre class="brush: sql;">SQL: SELECT 'Rodrigo '||'Valentim' FROM dual;
'RODRIGO'||'VALENTIM'
---------------------
Rodrigo Valentim
</pre>
<p><strong>2. Colocando a primeira letra do texto como Maiúscula.<br />
</strong>
<pre class="brush: sql;">SQL: SELECT INITCAP('rodrigo valentim') FROM dual;
INITCAP('RODRIGOVALENTIM')
--------------------------
Rodrigo Valentim
</pre>
<p><strong>3. Alternar entre Maiúscula e Minúscula</strong></p>
<pre class="brush: sql;">SQL: SELECT LOWER('RODRIGO ')||UPPER('valentim') FROM dual;
LOWER('RODRIGO')||UPPER('VALEN
------------------------------
rodrigo VALENTIM
</pre>
<p><strong>4. Convertendo letras em códigos ASCII</strong></p>
<pre class="brush: sql;">SQL: SELECT ASCII('A') FROM dual;
ASCII('A')
----------
65

SQL: SELECT ASCII('Z') FROM dual;
ASCII('Z')
----------
90

SQL: SELECT ASCII('a') FROM dual;
ASCII('A')
----------
97

SQL: SELECT ASCII('z') FROM dual;
ASCII('Z')
----------
122

SQL: SELECT ASCII(' ') FROM dual;
ASCII('')
----------
32
</pre>
<p><strong>5. Localizando a posição uma string no meio do texto</strong><br />
Com a função INSTR, é possível localizar caracteres dentro de um texto, de forma normal ou inversa.</p>
<p>Localizando a primeira posição da string no texto</p>
<pre class="brush: sql;">
SQL: SELECT INSTR('Exemplo de como realizar pesquisa em uma string', 'r', 1, 1) localiza_1 from dual;
LOCALIZA_1
----------
17
</pre>
<p>Localizando a segunda posição da string no texto</p>
<pre class="brush: sql;">SQL: SELECT INSTR('Exemplo de como realizar pesquisa em uma string', 'r', 1, 2) localiza_2 from dual;
LOCALIZA_2
----------
24
</pre>
<p>Localizando a terceira posição da string no texto</p>
<pre class="brush: sql;">SQL: SELECT INSTR('Exemplo de como realizar pesquisa em uma string', 'r', 1, 3) localiza_3 from dual;
LOCALIZA_3
----------
44
</pre>
<p>Localizando a quarta posição da string no texto, como não existe mais de 3 letras r no texto, ele retorna zero.</p>
<pre class="brush: sql;">SQL: SELECT INSTR('Exemplo de como realizar pesquisa em uma string', 'r', 1, 4) localiza_4 from dual;
LOCALIZA_4
----------
0
</pre>
<p>Para realizar a mesma pesquisa so que de ordem inversa, basta usar o valor negativo na função</p>
<pre class="brush: sql;">SQL: SELECT INSTR('Exemplo de como realizar pesquisa em uma string', 'r', -1, 1) localiza_1 from dual;
LOCALIZA_1
----------
44
</pre>
<p>Nestas condições, ele me retorna a primeira posição na ordem inversa, ou seja, a última.</p>
<p><strong>6. Atribuindo dígitos no final e/ou no inicio do texto.</strong><br />
Temos como usar o LPAD para inserir digitos na esquerda e RPAD para inserir digitos na direita.<br />
LPAD:</p>
<pre class="brush: sql;">SQL: SELECT LPAD('Rodrigo Valentim', 25, 'x') FROM dual;
LPAD('RODRIGOVALENTIM',25,'X')
------------------------------
xxxxxxxxxRodrigo Valentim
</pre>
<p>RPAD:
<pre class="brush: sql;">SQL: SELECT RPAD('Rodrigo Valentim', 25, 'x') FROM dual;
RPAD('RODRIGOVALENTIM',25,'X')
------------------------------
Rodrigo Valentimxxxxxxxxx
</pre>
<p><strong>7.Removendo dígitos do inicio ou do fim ou de ambos do texto</strong><br />
Podendo ser espaços em branco ou letras (TRIM só remove espaços em branco).<br />
LTRIM:</p>
<pre class="brush: sql;">SQL: SELECT '*' || LTRIM('               Rodrigo Valentim               ') || '*' FROM dual;
'*'||LTRIM('RODRIGOVALENTIM')|
---------------------------------
*Rodrigo Valentim               *
</pre>
<p>RTRIM:</p>
<pre class="brush: sql;">SQL: SELECT '*' || RTRIM('               Rodrigo Valentim               ') || '*' FROM dual;
'*'||RTRIM('RODRIGOVALENTIM')|
---------------------------------
*               Rodrigo Valentim*
</pre>
<p>TRIM:
<pre class="brush: sql;">SQL: SELECT '*'||TRIM('   Rodrigo Valentim   ')||'*' FROM dual;
'*'||TRIM('RODRIGOVALENTIM')||
------------------------------
*Rodrigo Valentim*
</pre>
<p><strong>8. Como inverter o conteúdo em uma string</strong></p>
<pre class="brush: sql;">SQL: select reverse('MITNELAV OGIRDOR') from dual;
REVERSE('MITNELAVOGIRDOR')
--------------------------
RODRIGO VALENTIM
</pre>
<p><strong>9. Substituindo Strings por outras Strings</strong><br />
Com a Função Replace é possível substituir o conjunto de caracteres por outro, no exemplo abaixo, ele vai alterar o valor DE para A</p>
<pre class="brush: sql;">SQL: SELECT REPLACE('ABCDE','DE','A') FROM dual;
REPLACE('ABCDE','DE','A')
-------------------------
ABCA
</pre>
<p><strong>10. Cortando conteúdo do texto com SUBSTR<br />
</strong>Com essa função, é possível exibir somente partes do texto. No exemplo abaixo, digo que quero iniciar meu texto da posição 3 e andar mais 9 dígitos.</p>
<pre class="brush: sql;">SQL: SELECT SUBSTR('Rodrigo Valentim', 3, 9) FIRST_FOUR FROM dual;
FIRST_FOUR
----------
drigo Val
</pre>
<p><strong>11. Descobrindo o tamanho da string com a função LENGTH.</strong></p>
<pre class="brush: sql;">SQL: SELECT LENGTH('Rodrigo Valentim') FROM dual;
LENGTH('RODRIGOVALENTIM')
-------------------------
16
</pre>
<p><strong>12. Retornando colunas com valor não nulo</strong><br />
Com a função COALESCE. Ela pesquisa entre as colunas passada e retorna o primeiro valor não nulo que foi encontrado.</p>
<pre class="brush: sql;">SQL: create table artigo_coalesce(col1 varchar2(10), col2 varchar2(10), col3 varchar2(10), col4 varchar2(10));
Table created
</pre>
<pre class="brush: sql;">
SQL: insert into artigo_coalesce values (NULL, NULL, 'C','D');
1 row inserted
SQL: insert into artigo_coalesce values (NULL, 'A', 'C','D');
1 row inserted
SQL: insert into artigo_coalesce values ('B', 'A', 'C','D');
1 row inserted
SQL: insert into artigo_coalesce values (NULL, 'D', NULL,'A');
1 row inserted
SQL: SELECT COALESCE(COL1, COL2, COL3, COL4) FROM artigo_coalesce;
COALESCE(COL1,COL2,COL3,COL4)
-----------------------------
C
A
B
D
</pre>
<p><strong>13.1 Pesquisando em uma string por um digito e exibindo o resto</strong><br />
Pesquisando em uma string por um digito e exibindo o resto da string pegando como base esse digito localizado. Bom, primeiro preciso saber qual a posição que preciso começar, neste caso, vou iniciar pela &#8216;\&#8217;. Vou pesquisar do fim para o inicio e localizar neste caso, a localização da ultima barra.</p>
<pre class="brush: sql;">SQL: select INSTR('c:\arquivo\arquivo.txt', '\', -1, 1) from dual;
INSTR('C:\ARQUIVO\ARQUIVO.TXT'
------------------------------
11
</pre>
<p>Depois de localizar, preciso então usar ela como ponto inicial e ir até o final da string completa. Como não sei o tamanho total da minha string, pois, pode ser que ela mude algum dia, vou usar a função LENGTH que me retornará o tamanho total.</p>
<pre class="brush: sql;">SQL: SELECT substr('c:\arquivo\arquivo.txt',INSTR('c:\arquivo\arquivo.txt', '\', -1, 1) ,length('c:\arquivo\arquivo.txt')) from dual;
SUBSTR('C:\ARQUIVO\ARQUIVO.TXT
------------------------------
\arquivo.txt
</pre>
<p>Depois de localizar o inicio e fim da minha string através das funções acima, preciso ajustar para que a barra não saia&#8230; a função SUBSTR está iniciando da posição 11 e indo até a posição final da string, por isso está me retornando a barra, então, preciso somar + 1 ao retorno da localização da &#8216;\&#8217;, para então ela não aparecer no meu resutlado.</p>
<pre class="brush: sql;">SQL: SELECT substr('c:\arquivo\arquivo.txt',INSTR('c:\arquivo\arquivo.txt', '\', -1, 1) + 1 ,length('c:\arquivo\arquivo.txt')) from dual;
SUBSTR('C:\ARQUIVO\ARQUIVO.TXT
------------------------------
arquivo.txt
</pre>
<p>Então, andando da posição 12 até a ultima posição, consigo através do substr cortar parte do texto e extrair somente o que desejo.</p>
<p><strong>13.2 Pegar uma String e inserir um valor no meio dela</strong><br />
Eu tenho uma String chamada &#8216;Existe Perfeita?&#8217; e quero inserir o Lógica no meio dela utilizando uma query&#8230;</p>
<p>Pegando trechos do ultimo exemplo (13.1) vamos montar nossa query e assim ter nosso retorno&#8230;</p>
<p>Primeiro preciso pegar o espaço em branco, levando em consideração que é o meio da string.</p>
<pre class="brush: sql;">SQL: SELECT instr('Existe Perfeita?',' ') FROM dual;
INSTR('EXISTEPERFEITA?','')
---------------------------
7
</pre>
<p>Agora vamos cortar somente o inicio da string, com SUBSTR vamos pegar da posição 1 até o espaço em branco (posição 7)</p>
<pre class="brush: sql;">SQL: SELECT substr('Existe Perfeita?',1,instr('Existe Perfeita?',' ')) FROM dual;
SUBSTR('EXISTEPERFEITA?',1,INS
------------------------------
Existe
</pre>
<p>Temos então somente o Existe. Vamos então inserir (concatenar) o texto que queremos e ter como resultado o Existe Lógica</p>
<pre class="brush: sql;">SQL: SELECT substr('Existe Perfeita?',1,instr('Existe Perfeita?',' '))||'Lógica' FROM dual;
SUBSTR('EXISTEPERFEITA?',1,INS
------------------------------
Existe Lógica
</pre>
<p>Agora falta inserir a parte final&#8230; vamos então pegar a String inicial e então cortar a parte do meio até o fim. Já sei qual o meio e para descobrir o fim é só usar a função LENGTH e então temos o resultado que queremos.</p>
<pre class="brush: sql;">SQL: SELECT substr('Existe Perfeita?',1,instr('Existe Perfeita?',' '))||'Logica'||substr('Existe Perfeita?',instr('Existe Perfeita?',' '),length('Existe Perfeita?')) "Existe?" FROM dual;
Existe?
-----------------------
Existe Logica Perfeita?
</pre>
<p>Acredito que tenha conseguido passar um pouco do que é trabalhar com Strings no Oracle&#8230;</p>
<p>Espero ter esclarecido algumas dúvidas e as que não foram esclarecidas, podem me procurar que eu vou tentar ajudar!</p>
<p>Abraço e até a próxima.</p>
<p><em>Rodrigo Valentim é Analista de Sistemas Oracle Developer</em><br />
<a href="http://www.rodrigovalentim.com/blog">http://www.rodrigovalentim.com/blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/06/03/trabalhando-com-strings-no-oracle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Execução ordenada nas triggers</title>
		<link>http://glufke.net/2009/05/14/execucao-ordenada-nas-triggers_oracle11g/</link>
		<comments>http://glufke.net/2009/05/14/execucao-ordenada-nas-triggers_oracle11g/#comments</comments>
		<pubDate>Thu, 14 May 2009 12:41:49 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[Triggers]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=95</guid>
		<description><![CDATA[A partir do Oracle 8i é possível criar mais de uma trigger do mesmo tipo na mesma tabela. Exemplo: duas triggers AFTER EACH ROW on INSERT. O tipo de trigger determina a ordem de execução: As BEFORE são executadas antes, e as AFTER depois. Contudo, como saber qual trigger executará primeiro quando se tem duas [...]]]></description>
			<content:encoded><![CDATA[<p>A partir do Oracle 8i é possível criar mais de uma trigger do mesmo tipo na mesma tabela. Exemplo: duas triggers AFTER EACH ROW on INSERT. O tipo de trigger determina a ordem de execução: As BEFORE são executadas antes, e as AFTER depois. Contudo, como saber qual trigger executará primeiro quando se tem duas AFTER EACH ROW on INSERT ?<span id="more-95"></span><br />
A execução das triggers neste caso seria algo &#8220;randomico&#8221;, pois não havia uma forma de definir a ordem de execução.
<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>No Oracle 11g, você pode adicionar uma cláusula que força a ordem de execução das triggers:</p>
<pre class="brush: sql;">create or replace trigger tr_pay_follow_up
before update
on payments
for each row
FOLLOWS TRIGGER_ANTERIOR
begin
... etc ...</pre>
<p>Neste caso a cláusula FOLLOWS força que a trigger seja disparada apenas após a trigger citada.</p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/05/14/execucao-ordenada-nas-triggers_oracle11g/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Utilizando Table of Record</title>
		<link>http://glufke.net/2009/05/04/utilizando-table-of-record/</link>
		<comments>http://glufke.net/2009/05/04/utilizando-table-of-record/#comments</comments>
		<pubDate>Mon, 04 May 2009 16:19:39 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[table of record]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=93</guid>
		<description><![CDATA[Hoje vamos ver o quanto é bom explorar certos recursos da ferramenta de Desenvolvimento Oracle. Sabe aquela rotina bem dinâmica que você não imagina como poderá resolver? Agora, imagine tentar guardar tudo isso em memória… Melhorou um pouco, correto? Vamos ver como é bom trabalhar com registros de memória no Oracle.




Primeiro passo é criar a [...]]]></description>
			<content:encoded><![CDATA[<p>Hoje vamos ver o quanto é bom explorar certos recursos da ferramenta de Desenvolvimento Oracle. Sabe aquela rotina bem dinâmica que você não imagina como poderá resolver? Agora, imagine tentar guardar tudo isso em memória… Melhorou um pouco, correto? Vamos ver como é bom trabalhar com registros de memória no Oracle.<br />
<span id="more-93"></span>
<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>Primeiro passo é criar a especificação de uma Package.</p>
<pre class="brush: sql;">PACKAGE PKG_EX_TABLE_RECORD IS
--Um Cursor é necessário para criar a “Table Of Cursor%ROWTYPE”,
--mesmo que não seja usado, pois o tipo a ser criado deve se
--basear em uma tabela ou um cursor
  CURSOR cExemplo IS
    SELECT cod_funcionario
      FROM empresa;

   -- Tipo: Coleção de registros
   TYPE tExemplo IS TABLE Of cExemplo%Rowtype INDEX BY binary_integer;

   -- Variável do tipo coleção de registros
   vExemplo tExemplo;

   --variável para os valores do cursor (não se pode atribuir
   --diretamente um registro do cursor à variável da coleção)
   vRec cExemplo%rowtype;
   -- índice
   x integer;
END;</pre>
<p>Agora, vamos ver como armazenar informações nesse registro de memória.</p>
<pre class="brush: sql;">DECLARE
  --vamos ver os funcionarios que tem salario menor que 2000 reais.
  CURSOR cEmpregados IS
  SELECT cod_funcionario
  FROM empresa
  WHERE func_sal <= 2000;

BEGIN
  –-iniciando o valor do indice
  PKG_EX_TABLE_RECORD.x := 0;
  FOR regfunc IN cEmpregados LOOP
    -- x é o indice para o registro, estou atritubindo mais 1 a ele de
    -- acordo com o que já existe, tipo uma sequence. Pego o ultimo
    -- valor e somo mais um.
    PKG_EX_TABLE_RECORD.x := nvl(PKG_EX_TABLE_RECORD.vExemplo.last,0) + 1;

    --atribui os valores do cursor (cConta_Produtos)
    --ao array de elementos
    PKG_EX_TABLE_RECORD.vExemplo(PKG_EX_TABLE_RECORD.x).cod_funcionario := regfunc.cod_funcionario;
  END LOOP;
END;</pre>
<p>Agora, chegou a hora de ver conteúdo do registro de memória.</p>
<pre class="brush: sql;">--Com um for loop, vamos varrer todo o registro
--de memória afim de recuperar os valores

--dessa forma, pego o ultimo valor caso exista.
FOR j IN 1..nvl(PKG_EX_TABLE_RECORD.vExemplo.last,0) LOOP 

  --uma nova opção está sendo utilizada, para então
  --ser possível ver se existe registro antes de
  --excluir, caso contrario, dará um erro por nao achar o registro
  IF PKG_EX_TABLE_RECORD.vExemplo.EXISTS(j) THEN
    --Verifica se o código do funcionario é igual ao listado abaixo,
    --assim, posso destaca-lo de alguma forma na tela
     IF PKG_EX_TABLE_RECORD.vExemplo(j).cod_funcionario = consulta.cod_funcionario THEN
       --ao localizar, uma ação será realizada
        (…)
     END IF;
  END IF;
END LOOP;</pre>
<p>Pronto. Agora, não podemos esquecer de inserir uma função para limpar a memória quando você achar que não mais irá utiliza-la.</p>
<pre class="brush: sql;">--vamos então varrer todo o registro de memória
FOR j IN 1..nvl(PKG_EX_TABLE_RECORD.vExemplo.last,0) LOOP

  --uma nova opção está sendo utilizada, para então ser possível
  --ver se existe registro antes de excluir, caso contrario,
  --dará um erro por nao achar o registro
  IF PKG_EX_TABLE_RECORD.vExemplo.EXISTS(j) THEN

    --Deletando registro de memoria. Uma vez deletado, a posição J
    --ficará sempre vazia, por isso a necessidade de usar o exists
     pkg_aviso_cirurgia.vAvisoCir.DELETE(j);
  END IF;

--Fim do Loop para verificar os agendamentos localizados
END LOOP;  </pre>
<p>Pronto, agora já é possível arriscar na solução de algum problema que precise dessa rotina, ela pode ser utilizada da forma mais fácil até a mais complexa…</p>
<p><em>Rodrigo Valentim é Analista de Sistemas Oracle Developer</em><br />
<a href="http://www.rodrigovalentim.com/blog">http://www.rodrigovalentim.com/blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2009/05/04/utilizando-table-of-record/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Limpar Table of varchar</title>
		<link>http://glufke.net/2008/10/12/limpar-table-of-varchar/</link>
		<comments>http://glufke.net/2008/10/12/limpar-table-of-varchar/#comments</comments>
		<pubDate>Mon, 13 Oct 2008 02:39:44 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[table of record]]></category>

		<guid isPermaLink="false">http://glufke.net/?p=29</guid>
		<description><![CDATA[Essa semana surgiu uma dúvida no forum sobre variáveis TABLE of Varchar: Como zerar um array de varchar ? Aí vai a solução&#8230;
Basta setar uma variável vazia em cima da original. Abaixo um exemplo:
-- delete Pl/SQL table records
declare
  type myTextTableType is table of varchar2(200) index by binary_integer;

  l_tabela_texto      [...]]]></description>
			<content:encoded><![CDATA[<p>Essa semana surgiu uma dúvida no forum sobre variáveis TABLE of Varchar: Como zerar um array de varchar ? Aí vai a solução&#8230;<span id="more-29"></span><br />
Basta setar uma variável vazia em cima da original. Abaixo um exemplo:</p>
<pre class="brush: sql;">-- delete Pl/SQL table records
declare
  type myTextTableType is table of varchar2(200) index by binary_integer;

  l_tabela_texto      myTextTableType;
  l_tabela_vazia      myTextTableType;
begin
  l_tabela_texto(10) := 'Um valor';
  l_tabela_texto(20) := 'outro valor';
  l_tabela_texto(30) := 'mais um valor';

  l_tabela_texto := l_tabela_vazia;
  dbms_output.put  ('Uma vez que setamos nossa tabela VAZIA p/ uma TABELA POPULADA, ela se torna vazia.');
  dbms_output.put_line('Quantidade: ' || l_tabela_texto.count || ' varchars');

end;
/ </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> set serveroutput on
SQL>
SQL> -- delete Pl/SQL table records
SQL> declare
  2    type myTextTableType is table of varchar2(200) index by binary_integer;
  3
  4    l_tabela_texto      myTextTableType;
  5    l_tabela_vazia    myTextTableType;
  6  begin
  7    l_tabela_texto(10) := 'Um valor';
  8    l_tabela_texto(20) := 'outro valor';
  9    l_tabela_texto(30) := 'mais um valor';
 10
 11    l_tabela_texto := l_tabela_vazia;
 12    dbms_output.put  ('Uma vez que setamos nossa tabela VAZIA p/ uma TABELA POPULADA, ela se torn
a vazia.');
 13    dbms_output.put_line('Quantidade: ' || l_tabela_texto.count || ' varchars');
 14
 15  end;
 16  /
Uma vez que setamos nossa tabela VAZIA p/ uma TABELA POPULADA, ela se torna
vazia.Quantidade: 0 varchars

PL/SQL procedure successfully completed.

SQL> </pre>
<p>Comentários <a href="http://glufke.net/oracle/viewtopic.php?t=3738">aqui</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2008/10/12/limpar-table-of-varchar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transformar linhas do SQL em string delimitada</title>
		<link>http://glufke.net/2007/09/12/transformar-linhas-do-sql-em-string-delimitada/</link>
		<comments>http://glufke.net/2007/09/12/transformar-linhas-do-sql-em-string-delimitada/#comments</comments>
		<pubDate>Wed, 12 Sep 2007 20:02:00 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[String]]></category>
		<category><![CDATA[Utilidade]]></category>

		<guid isPermaLink="false">http://glufke.net/2007/09/12/transformar-linhas-do-sql-em-string-delimitada/</guid>
		<description><![CDATA[Essa procedure pode ser muito útil em algumas situações: Ela pega as linhas de uma coluna e retorna cada linha separada por ví­rgula na mesma string. 
CREATE OR REPLACE FUNCTION rowtocol (
   p_slct IN VARCHAR2,
   p_dlmtr IN VARCHAR2 DEFAULT ',' ) RETURN VARCHAR2 AUTHID CURRENT_USER
AS
   TYPE c_refcur IS REF [...]]]></description>
			<content:encoded><![CDATA[<p>Essa procedure pode ser muito útil em algumas situações: Ela pega as linhas de uma coluna e retorna cada linha separada por ví­rgula na mesma string. <span id="more-14"></span></p>
<pre class="brush: sql;">CREATE OR REPLACE FUNCTION rowtocol (
   p_slct IN VARCHAR2,
   p_dlmtr IN VARCHAR2 DEFAULT ',' ) RETURN VARCHAR2 AUTHID CURRENT_USER
AS
   TYPE c_refcur IS REF CURSOR;
   lc_str VARCHAR2(4000);
   lc_colval VARCHAR2(4000);
   c_dummy c_refcur;
   l number;
BEGIN
   OPEN c_dummy FOR p_slct;
   LOOP
     FETCH c_dummy INTO lc_colval;
     EXIT WHEN c_dummy%NOTFOUND;
     lc_str := lc_str || p_dlmtr || lc_colval;
   END LOOP;
   CLOSE c_dummy;
   RETURN SUBSTR(lc_str,2);
END;
</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>Agora vamos ao exemplo:</p>
<pre class="brush: sql;">SQL> CREATE OR REPLACE FUNCTION rowtocol (
  2     p_slct IN VARCHAR2,
  3     p_dlmtr IN VARCHAR2 DEFAULT ',' )
  4  RETURN VARCHAR2
  5     AUTHID CURRENT_USER AS
  6     TYPE c_refcur IS REF CURSOR;
  7     lc_str VARCHAR2(4000);
  8     lc_colval VARCHAR2(4000);
  9     c_dummy c_refcur;
 10     l number;
 11  BEGIN
 12     OPEN c_dummy FOR p_slct;
 13     LOOP
 14       FETCH c_dummy INTO lc_colval;
 15       EXIT WHEN c_dummy%NOTFOUND;
 16       lc_str := lc_str || p_dlmtr || lc_colval;
 17     END LOOP;
 18     CLOSE c_dummy;
 19     RETURN SUBSTR(lc_str,2);
 20  END;
 21  /

Function created.

SQL> SELECT ROWTOCOL('SELECT ENAME FROM EMP') FROM DUAL;

ROWTOCOL('SELECTENAMEFROMEMP')
------------------------------------------------------------------
SMITE,ALLEN,WARD,JONES,MARTIN,BLAKE,SCOTT,TURNER,ADAMS,JAMES,FORD

SQL></pre>
<p>Comente <a href="http://glufke.net/oracle/viewtopic.php?t=31">aqui</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2007/09/12/transformar-linhas-do-sql-em-string-delimitada/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comparação de Campos com NULL</title>
		<link>http://glufke.net/2007/09/06/comparacao-de-campos-com-null/</link>
		<comments>http://glufke.net/2007/09/06/comparacao-de-campos-com-null/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 13:34:52 +0000</pubDate>
		<dc:creator>glufke</dc:creator>
				<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[Curiosidade]]></category>
		<category><![CDATA[NULL]]></category>

		<guid isPermaLink="false">http://glufke.net/2007/09/06/comparacao-de-campos-com-null/</guid>
		<description><![CDATA[Sabemos que quando um variável ou um campo no Oracle está NULL, ele não pode ser simplesmente comparado a um outro valor, pois o resultado da compração também será false!

declare
  a number:=null;
  b number:=null;
begin
  if a=b
  then dbms_output.put_line('SIM');
  else  dbms_output.put_line('nao');
  end if;
end;

SQL> /
nao



POUCO EFICIENTE
Para &#8220;sanar&#8221; este problema, é [...]]]></description>
			<content:encoded><![CDATA[<p>Sabemos que quando um variável ou um campo no Oracle está NULL, ele não pode ser simplesmente comparado a um outro valor, pois o resultado da compração também será false!<span id="more-10"></span></p>
<pre class="brush: sql;">
declare
  a number:=null;
  b number:=null;
begin
  if a=b
  then dbms_output.put_line('SIM');
  else  dbms_output.put_line('nao');
  end if;
end;

SQL> /
nao
</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><strong>POUCO EFICIENTE</strong><br />
Para &#8220;sanar&#8221; este problema, é possivel usar NVL, que não é uma boa prática. Veremos porque:</p>
<pre class="brush: sql;">
if nvl(a, 123456789) = nvl(b, 123456789)
then --seu código
</pre>
<p>O exemplo acima até funciona se o valor for diferente de 123456789. Se o valor for igual, ferra a comparação!</p>
<p><strong>MUITO EFICIENTE</strong><br />
A melhor prática possível<br />
É um pouco trabalhosa, mas sempre funcionará:</p>
<pre class="brush: sql;">
if a<>b
or (a is null and b is not null)
or (a is not null and b is null)
then --seu codigo
</pre>
<p>Comente <a href="http://glufke.net/oracle/viewtopic.php?p=343">aqui</a></p>
]]></content:encoded>
			<wfw:commentRss>http://glufke.net/2007/09/06/comparacao-de-campos-com-null/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

