Tokenizer - Percorrer string c/ campos sep. por ";"

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
Filipe_Geissler
Rank: Programador Júnior
Rank: Programador Júnior
Mensagens: 16
Registrado em: Qua, 08 Fev 2006 9:17 am
Localização: Canoas - RS

Boa tarde!!

Estou lendo uma planilha do excel no forms, com PL/SQL usando o TEXT_IO. Cada linha possui os campos que estão separador por ";", sendo que que tenho que pegar cada um desses campos e jogar numa variável. Acredito que alguém já deve ter feito isso, ou algo parecido, será que alguém poderia me dar uma dica????

ps: eu sei que com o SqlLoader é muito fácil, até já fiz, mais nesse caso tem q ser assim mesmo, na mão!

Obrigado pela atenção!!
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Eu tenho uma rotina interessante, mas acho que não se aplica ao seu caso. Essa rotina é mais util na passagem de parametros quando não se sabe o número de parametros de entrada...

Dá uma olhada:

Selecionar tudo

set ver off
def Del='@'
def String="@0@11@222@3333@44444@555555@6666666@77777777@888888888"

select
Rownum Row#,
SUBSTR(A.Str||'&Del'
, INSTR(A.Str||'&Del' , '&Del', 1, Rownum ) +1
, INSTR(A.Str||'&Del' , '&Del', 1, Rownum+1)
-INSTR(A.Str||'&Del' , '&Del', 1, Rownum ) -1
) Token
From
(
select
'&String' Str
from dual
)
A,
all_objects B
where
Rownum< length(A.Str)-length(REPLACE(A.Str,'&Del'))+1
;


ROW#       TOKEN
---------- -------------------------------------------------------
1          0
2          11
3          222
4          3333
5          44444
6          555555
7          6666666
8          77777777
9          888888888

Creio que você conseguirá com INSTR fazer essa sua... coloca um LOOP e vai pegando o SUBSTR entre um ; e outro...
:-o
Filipe_Geissler
Rank: Programador Júnior
Rank: Programador Júnior
Mensagens: 16
Registrado em: Qua, 08 Fev 2006 9:17 am
Localização: Canoas - RS

Consegui:

Selecionar tudo

begin
	
	in_file := Text_IO.Fopen(filename, 'r');
	-- loop para percorrer todas a linhas do arquivo
	LOOP
    begin
    	Text_IO.Get_Line(in_file, linebuf);
    	i := 0;
    	numseparador := 1;
    	aux := null;
    	-- for para percorrer a linha caracter à caracter
			for i in 1..length(linebuf) loop
    		caracter := ( substr(linebuf, i, 1));
    		-- cada vez que achar o separador ";", separa o campo
    		if caracter = ';' then
    			if numseparador = 1 then 
    				ano := aux;
    			elsif numseparador = 2 then 
    				mês := aux;
    			elsif numseparador = 3 then 
    				pv := aux;
    			elsif numseparador = 4 then
    				valor_fat := aux;
    			end if;
    			-- incrementa o separador, que vai indicar o proximo campo
    			numseparador := numseparador + 1;
    			aux := null;    			
    		-- se não achar o separador, vai montando o campo ate achar o separador
    		else
    			aux := aux || caracter;
    		end if;		   		
    	end loop;
    	message(ano || ' - ' || mês || ' - ' || pv || ' - ' || valor_fat);
    	-- validações aqui...
		exception
		  when no_data_found then
		    Text_IO.Fclose(in_file);
		    exit;
		end;
	END LOOP;
	
end;
Esse codigo lê o arquivo linha a e percorre a linha caracter a caracter até achar o ";", quando acha o ";" joga a string montada em "aux" na variável...
Funcionou muito bem. Postei aqui para deixar como consulta para outra pessoa!!
Qualquer dúvida é só falar!!!

falow
Avatar do usuário
leobbg
Rank: Programador Júnior
Rank: Programador Júnior
Mensagens: 22
Registrado em: Sex, 29 Out 2004 10:25 am
Localização: PORTO ALEGRE - RS
Leo BBG Consultor Oracle

Para quem gosta de utilizar pl/table ai vai..

Selecionar tudo

/********************************************************************************************/
  /* Rotina responsável em separar "cargas" de dados que utilizam um separador em um "array"  */
  /********************************************************************************************/
  procedure prc_separa_texto( pTexto in varchar2, pSeparador in varchar2 default null ) is
    --
    pSeparador varchar2(1);
    --
    vContador number := 1;
	  vInicio   number := 1;
	  vFim      number := 0;
	  --
	  type tG_Array_Texto is table of varchar2(4000) index by binary_integer;
    vG_Texto_Separado tG_Array_Texto;
    --
	begin
	  --
	  loop
	    --
	    vFim := instr( pTexto, pSeparador, 1, vContador );
	    --
	    exit when vFim = 0;
	    --
	    vG_Texto_Separado(vContador) := substr( pTexto, vInicio, vFim - vInicio );
	    --
	    vInicio   := vFim      + 1;
	    vContador := vContador + 1;
	    --
	  end loop;
    --
  end;
8)
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Outra forma de "tokenizar".
É necessário a criação do type TP_VARCHAR2 com o comando abaixo:

Selecionar tudo

CREATE TYPE TP_VARCHAR2 AS TABLE OF VARCHAR2(2000)

Selecionar tudo

CREATE OR REPLACE FUNCTION FNC_TOKENIZER(P_STRING    IN VARCHAR2,
                                         P_SEPARADOR IN VARCHAR2)
   RETURN TP_VARCHAR2 PIPELINED IS
   l_string LONG DEFAULT p_string || p_separador;
   n        NUMBER;
   /*----------------------------------------------------------------------*/
   /* Nome : FNC_PHW_TOKENIZER                                             */
   /* Descrição : Função para separação, em linhas diferentes, de valo-    */
   /* res de uma lista que utilize algum tipo de separador                 */
   /* Ex.: "A, B, C", separa cada letra num linha diferente                */
   /* Utilização:                                                          */
   /* select column_value valor from TABLE(fnc_tokenizer('A,B,C',','))     */
   /* Autor : Getulio Holtz (TechnoCorp)                                   */
   /* Data : 27 de Setembro de 2006                                        */
   /* É necessário a criação do tipo TP_VARCHAR2 com o comando abaixo:     */
   /* CREATE TYPE TP_VARCHAR2 AS TABLE OF VARCHAR2(2000)                   */
   /*----------------------------------------------------------------------*/


BEGIN
   LOOP
      EXIT WHEN nvl(l_string,' ') = ' ';
      n := instr(l_string,
                 p_separador);
      dbms_output.put_line(n);
      PIPE ROW(ltrim(rtrim(substr(l_string,
                                  1,
                                  n - 1))));
      l_string := substr(l_string,
                         n + 1);
   END LOOP;
   RETURN;
END FNC_TOKENIZER;
/
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Aqui vai mais uma forma de tokenizar, contribuiçao do Paulo Diniz (Mato Grosso do Sul)
Isso usa expressões regulares e CONNECT BY :-)

Selecionar tudo

select REGEXP_SUBSTR(str, exp, 1, level) lista
from (select 'paulo@email.com;thomas@email.com' str, '[^;]+' exp 
      from dual) 
connect by REGEXP_SUBSTR(str, exp, 1, level) is not null 
Saida:

Selecionar tudo

LISTA
--------------------------------
paulo@email.com
thomas@email.com
Tem um documento dele que explica como fazer o contrário disso, ou seja: pegar diversas linhas e agrupar em uma so, delimitado por um caracter. (utilizando a função nativa do 11g chamado LISTAGG).
https://docs.google.com/file/d/0B7CiEAx ... t?hl=en_US
ou
http://www.linkedin.com/groups/Converte ... RITM-title
Responder
  • Informação