Framework

Import CSV via BLOB

BY KARL HAJEK

CSV-Dateien direkt über ein Oracle BLOB importieren

Immer wieder kommt die Frage, wie man CSV-Dateien via PL/SQL importieren kann, wenn man keinen Zugriff auf das Dateiverzeichnis des Datenbankservers hat. Ich habe in diesem Artikel ein Beispiel vorbereitet, das die grundlegende Vorgehensweise darstellt und leicht an die individuellen Bedürfnisse angepasst werden kann. Dieses Beispiel liest Zeitbuchungen verschiedener Terminals und importiert diese in die dafür vorgesehene Importtabelle MDZEIMP. Die Funktion enthält ein BLOB als Input-Parameter, welches vom Client übergeben wird.

CREATE OR REPLACE PROCEDURE Ind_ImportCSV(theFile IN BLOB) IS
	sourceCharSet VARCHAR2(40) := 'AL32UTF8';
	dbCharSet VARCHAR2(40) := Md_Sql.GetDBCharSet;
	m_File UTL_FILE.FILE_TYPE;
	theLine VARCHAR2(200);
	isFirst BOOLEAN := true;
	rec mdzeimp%ROWTYPE;
BEGIN
	-- create an oracle directory 'IMPORT' first
	Md_Lib.WriteBlobToFile(Md_Zip.UnzipBlob(theFile), 'IMPORT', 'Imp_ZE.csv');
	m_File := UTL_FILE.FOPEN ('IMPORT', 'Imp_ZE.csv', 'r', 200);

	-- sets the default delimiter of the CSV file
	Md_ImpLieItm.SetDelimiter(';');

	loop
		begin
			theLine := NULL;
			UTL_FILE.GET_LINE (m_File, theLine);

			if (TRIM(theLine) is null) then
				exit;
			end if;

			exception
				when NO_DATA_FOUND then
					exit;
		end;

		if (isFirst) then
			-- ignore header line
			isFirst := false;
		else
			--Card_Nr;time;Come/Go;Device_ID
			--1046;04.01.2016 07:05;G;5
    
			--activate this line when to convert to a different charset
			--theLine := CONVERT(theLine, dbCharSet, sourceCharSet);

			rec.Card_Nr := Md_ImpLieItm.Extract(theLine);
			rec.StartTime := TO_DATE(Md_ImpLieItm.Extract(theLine), 'DD.MM.YYYY HH24:MI');
			rec.Zea_Code := Md_ImpLieItm.Extract(theLine);
			rec.Terminal := TO_NUMBER(Md_ImpLieItm.Extract(theLine));
			rec.Terminal_Type := 'FP';
    
			insert into mdzeimp values rec;
		end if;
	end loop;

	commit;
	UTL_FILE.FCLOSE(m_File);

	exception
		when OTHERS then
			if (UTL_FILE.IS_OPEN (m_File)) then	UTL_FILE.FCLOSE(m_File); end if;
			Md_Error.Raise;
END;
/

Die BLOB-Datei wird zuerst im Oracle-Verzeichnis 'IMPORT' gespeichert (dieses muss vorher angelegt werden falls noch nicht vorhanden). Danach wird mit UTL_FILE jede Zeile einzeln gelesen und verarbeitet. Mit Hilfe des Packages Md_ImpLieItem werden die Felder der CSV-Datei extrahiert und den Feldern der Tabelle zugewiesen.

Was jetzt noch fehlt ist das entsprechende Command für das Hochladen der CSV-Datei, das wir direkt im Hauptmenü des HRM-Moduls platzieren. Daher definieren wir dieses Command im XML-Repository der Datei RBI_PREMIUM#EXTENSION:

<?xml version="1.0"?>
<ResourceBundleInfoContainer xmlns:mdc="http://www.multidata.at/mp5/Common" xmlns="http://www.multidata.at/mp5" >
	<CommandsCatalog>
		<Command Name="Ind.ZeUpload" Title="Upload terminal data" Mode="DbCall" Action="Ind_ImportCSV">
			<Parameters>
				<mdc:Parameter Name="theFile" DataType="Blob" Title="File" Value="D:\Temp\Terminal.csv" Display="true"/>
			</Parameters>
		</Command>
	</CommandsCatalog>
	<MenusCatalog>
		<MenuBarItem Title="Zeiterfass&amp;ung">
			<MenuBarItem Title="Importe">
				<MenuBarItem CommandName="Ind.ZeUpload" BeginGroup="true" />
			</MenuBarItem>
		</MenuBarItem>
	</MenusCatalog>
</ResourceBundleInfoContainer>