Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Ler e importar arquivos CSV no Oracle PL/SQL com eficiência

O exemplo é fornecido abaixo para ler e importar CSV arquivo (delimitado por vírgula) em PLSQL. Existe um pacote no Oracle forms "D2k_Delimited_String" que usamos para ler e importar arquivo delimitado por vírgula (ou qualquer delimitador), escrevi um post também no Oracle Forms para ler arquivos delimitados com este pacote, segue o link https:/ /www.foxinfotech.in/2013/02/reading-and-importing-comma-delimited.html. O mesmo pacote que converti em pacote de banco de dados para ler arquivo CSV em PLSQL de forma eficiente, renomeei o pacote para "Plsql_Delimited_String". Abaixo está um exemplo dado para importar arquivo csv em PL SQL com a ajuda desta função de pacote Get_String, o seguinte é o uso desta função:

Plsql_Delimited_String.Getstring ([string contendo texto delimitado, a linha inteira],
[ocorrência],
[não terminada booleana default false],
[delimeter]);

No procedimento a seguir, o usuário passará um nome de arquivo que deve estar no local do diretório criado no objeto de diretório Oracle, neste exemplo o objeto de diretório 'YOUR_DIRECTORY' é usado, altere-o com seu objeto de diretório e copie o arquivo delimitado nesse local e passe o nome do arquivo para este procedimento.
CREATE OR REPLACE PROCEDURE Import_Emp_File (P_FILENAME IN VARCHAR2,
o_msg OUT VARCHAR2)
IS
Infile UTL_FILE.File_Type;
Linebuf VARCHAR2 (4000);
V_Getstring VARCHAR2 (100) );

-- Field Values ​​Array
TYPE Fieldvalue IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;

Field_Position Fieldvalue;

Total_Rec_Count NUMBER :=0;
Total_Rec_Processed NUMBER :=0;
BEGIN
Infile :=UTL_FILE.Fopen ('YOUR_DIRECTORY', P_FILENAME, 'R');

LOOP
---
UTL_FILE.Get_Line (Infile, Linebuf);
-- adicionando pipe extra no final da linha para ler todos os campos

Linebuf :=Linebuf || '|';

-- Suponha que o arquivo contém Seis strings delimitadas com pipe (|)
FOR I IN 1 .. 6
LOOP
Field_Position (I) :=
Plsql_Delimited_String.Getstring (Linebuf ,
I,
FALSE,
'|');
END LOOP;

BEGIN
Total_Rec_Count :=Total_Rec_Count + 1;

-- uma tabela de exemplo
INSERT INTO EMP (EMPLOYEE_NUMBER,
FIRST_NAME,
LAST_NAME,
DATE_OF_JOIN,
EMP_TYPE,
DATE_OF_REGN)
VALUES (field_position (1),
field_position (2),
field_position (3),
field_position (4),
field_position (5),
field_position (6) );

Total_Rec_Processed :=Total_Rec_Processed + 1;
EXCEÇÃO
QUANDO OUTROS
ENTÃO
-- ignorando erro durante a inserção do banco de dados
NULL;
END;
FIM DO LOOP;

IF UTL_FILE.is_open (infile)
THEN
UTL_FILE.Fclose (Infile);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
IF UTL_FILE.is_open (arquivo)
ENTÃO
UTL_FILE.Fclose (arquivo);
END IF;

SE total_rec_processed> 0
ENTÃO
COMMIT;
END IF;
QUANDO OUTROS
ENTÃO
SE UTL_FILE.is_open (infile)
ENTÃO
UTL_FILE.Fclose (Infile);
END IF;

o_msg :=SQLERRM;
END;
/A seguir está a fonte do pacote PLSQL_DELIMITED_STRING usado neste exemplo, instale este pacote em seu esquema. O pacote contém muitas outras funções utilitárias que podem ser usadas para ler o arquivo csv usando PLSQL:
CRIAR OU SUBSTITUIR PACOTE plsql_Delimited_String IS

function Counter( Source_string em varchar2,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',') return number;
Procedure PutString( Source_string in out varchar2,
String_to_add in varchar2,
Field_position in number,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',');
Procedure PutNumber( Source_string in out varchar2,
number_to_add in number,
Field_position in number,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',');
Procedure PutDate( Source_string in out varchar2,
Date_to_add in date,
Field_position in number,
UnTerminated in Bo olean default FALSE,
Delimiter in varchar2 default ',');
function GetString( Source_string em varchar2,
Field_position in number,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',') return varchar2;
function GetNumber( Source_string em varchar2,
Field_position in number,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ', ') return number;
function GetDate( Source_string in varchar2,
Field_position in number,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',') return date;
função Locate( Source_string em varchar2,
Search_String em varchar2,
UnTerminated in Boole um default FALSE,
Delimiter in varchar2 default ',') return number;
function Locate( Source_string in varchar2,
Search_date in date,
UnTerminated in Boolean default FALSE,
/> Delimitador em varchar2 default ',') return number;
function Locate( Source_string em varchar2,
Search_number em número,
UnTerminated in Boolean default FALSE,
Delimiter in varchar2 default ',') retorna número;
END plsql_Delimited_String;
/

CREATE OR REPLACE PACKAGE BODY plsql_Delimited_String
IS
FUNCTION Counter (Source_string IN VARCHAR2,
Unterminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN NUMBER
IS
iModifier PLS_INTEGER :=0;
iOldSize PLS_INTEGER :=LENGTH (Source_string);
BEGIN
IF Unterminated
THEN
iModifier :=1;
FIM SE;

RETURN (iOldSize - LENGTH (REPLACE (Source_string, Delimiter)))
+ iModifier;
END Contador;

PROCEDURE PutString (Source_string IN OUT VARCHAR2,
String_to_add IN VARCHAR2,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
IS
iStrLen PLS_INTEGER :=LENGTH (Source_String);
iStrFragLen PLS_INTEGER :=LENGTH (String_to_add);
iPtrStart PLS_INTEGER :=0;
iPtrEnd PLS_INTEGER :=0;
vcSepBuffer VARCHAR2 (2000);
iCounter PLS_INTEGER;
BEGIN
-- 1. a string é Comprimento Zero?
SE iStrLen =0
THEN
IF Field_Position> 1
THEN
PARA iCounter IN 2 .. Field_Position
LOOP
vcSepBuffer :=vcSepBuffer || Delimitador;
END LOOP;
END IF;

Source_string :=vcSepBuffer || String_to_add;

SE NÃO TERMINADO
ENTÃO
Source_string :=Source_String || Delimiter;
iStrLen :=LENGTH (Source_string);
END IF;
ELSE
-- 2. Lide com strings não terminadas
IF UnTerminated
THEN
Source_string :=Source_string || Delimitador;
FIM SE;

-- 3. Localize o separador nth-1
IF Field_Position> 1
THEN
LOOP
iPtrStart :=
(INSTR (Source_string || vcSepBuffer,
Delimiter,
1,
Field_Position - 1)
- 1)
+ LENGTH (Delimiter);
EXIT WHEN iPtrStart> 0;
vcSepBuffer :=vcSepBuffer || Delimitador;
END LOOP;

SE vcSepBuffer NÃO É NULL
ENTÃO
iPtrEnd :=iStrLen;
ELSE
iPtrEnd :=
INSTR (Source_string,
Delimiter,
1 ,
Field_Position);

SE iPtrEnd =0
ENTÃO
iPtrEnd :=iStrLen;
END IF;
END IF;
ELSE
iPtrStart :=0;
iPtrEnd :=
INSTR (Source_string,
Delimitador,
1,
Field_Position);

SE iPtrEnd =0
ENTÃO
iPtrEnd :=iStrLen;
END IF;
END IF;

-- 3. Reconstrua a string
Source_string :=
SUBSTR (Source_string, 1, iPtrStart)
|| vcSepBuffer
|| String_to_add
|| Delimitador
|| SUBSTR (Source_string, iPtrEnd + LENGTH (Delimitador));

-- 4. Classifique a terminação
SE não terminada
ENTÃO
Source_string :=
SUBSTR (Source_String,
1,
(LENGTH (Source_string) - LENGTH (Delimitador));
END IF;
END IF;
END PutString;

PROCEDURE PutNumber (Source_string IN OUT VARCHAR2,
number_to_add IN NUMBER,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
IS
BEGIN
-- 1. Basta fazer conversões de tipo de dados e chamar a varchar2 varsion de put..
plsql_Delimited_String.PutString (Source_string,
TO_CHAR (number_to_add),
Field_position,
UnTerminated,
Delimiter);
END PutNumber;

PROCEDURE PutDate (Source_string IN OUT VARCHAR2,
Date_to_add IN DATE,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
IS
BEGIN
-- 1. Basta fazer conversões de tipo de dados e chamar a varchar2 de put..
plsql_Delimited_String.
PutString (Source_string,
TO_CHAR (date_to_add, ' DD-MON-AAAA HH24:MI:SS'),
Field_position,
UnTerminated,
Delimiter);
END PutDate;

FUNCTION GetString (Source_string IN VARCHAR2,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN VARCHAR2
IS
iPtrEnd PLS_INTEGER :=0;
iPtrStart PLS_INTEGER :=0;
vcSourceStrCopy VARCHAR2 (2000) :=Source_string;
BEGIN
IF UnTerminated
THEN
vcSourceStrCopy :=vcSourceStrCopy || Delimitador;
FIM SE;

IF Field_Position> 1
THEN
iPtrStart :=
INSTR (vcSourceStrCopy,
Delimiter,
1,
Field_Position - 1)
+ LENGTH (Delimitador);
ELSE
iPtrStart :=1;
END IF;

iPtrEnd :=
INSTR (vcSourceStrCopy,
Delimitador,
1,
Field_Position);
RETURN SUBSTR (vcSourceStrCopy, iPtrStart, (iPtrEnd - iPtrStart));
FIM GetString; /* Versão da string */

FUNCTION GetNumber (Source_string IN VARCHAR2,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN NUMBER
IS
iRc PLS_INTEGER;
BEGIN
RETURN TO_NUMBER (GetString (Source_string,
Field_Position,
UnTerminated,
Delimiter));
END GetNumber; /* Versão do número */

FUNCTION GetDate (Source_string IN VARCHAR2,
Field_position IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN DATE
IS
BEGIN
RETURN TO_DATE (GetString (Source_string,
Field_Position,
UnTerminated,
Delimiter), 'DD-MON-YYYY HH24:MI:SS');
FIM GetData; /* Versão da data */

FUNCTION Localize (Source_string IN VARCHAR2,
Search_String IN VARCHAR2,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN NUMBER
IS
iHit PLS_INTEGER :=0;
iCounter PLS_INTEGER;
vcCompare VARCHAR2 (2000);
BEGIN
FOR iCounter IN 1 .. Counter (Source_String, UnTerminated, Delimiter)
LOOP
IF GetString (Source_String,
iCounter,
UnTerminated,
Delimiter) =Search_String
THEN
iHit :=iCounter;
SAIR;
FIM SE;
FIM LOOP;

RETURN iHit;
END Localizar;

FUNCTION Localize (Source_string IN VARCHAR2,
Search_date IN DATE,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN NUMBER
IS
BEGIN
RETURN Localize (Source_string,
TO_CHAR (Search_date, 'DD-MON-YYYY HH24:MI:SS'),
UnTerminated,
Delimiter);
FIM Localizar; /* Versão da data */

FUNCTION Localize (Source_string IN VARCHAR2,
Search_number IN NUMBER,
UnTerminated IN BOOLEAN DEFAULT FALSE,
Delimiter IN VARCHAR2 DEFAULT ',')
RETURN NUMBER
IS
BEGIN
RETURN Localize (Source_string,
TO_CHAR (Search_number),
UnTerminated,
Delimiter);
END Localize; /* Versão do Número */
END; /* Corpo */
/