Im deutschsprachigen APEX (HTML-DB) Forum kam heute die Frage auf, wie eine APEX-Anwendung aussehen muß, damit der Anwender selbständig CSV-Dateien importieren kann.
Da ich selber vor einiger Zeit eine Procedure dafür in meine Anwendung integriert habe, folgt hier der Code:
PROCEDURE import_csv (p_upload IN VARCHAR2) IS v_my_array wwv_flow_global.vc_arr2; empty_array wwv_flow_global.vc_arr2; v_array wwv_flow_global.vc_arr2; v_upload VARCHAR2 (32000) := NULL; v_line VARCHAR2 (32000) := NULL; bad_values EXCEPTION; BEGIN v_upload := REPLACE (p_upload, CHR (09), ':'); WHILE v_upload IS NOT NULL LOOP v_line := SUBSTR (v_upload, 1, INSTR (v_upload, CHR (10)) - 1); v_my_array := wwv_flow_utilities.string_to_table (v_line); IF v_my_array.COUNT != 3 -- hat die csv-datei die gewünschte Anzahl Spalten? THEN RAISE bad_values; ELSE v_array := empty_array; BEGIN EXECUTE IMMEDIATE 'INSERT INTO my_table(feld1,feld2,feld3) values (:1,:2,:3)' USING v_my_array (1), v_my_array (2), v_my_array (3); EXCEPTION WHEN OTHERS THEN dbms_output.put_line('Fehler'); END; v_upload := SUBSTR (v_upload, INSTR (v_upload, CHR (10)) + 1); END IF; END LOOP; END import_csv;
Um die Procedure aufzurufen, reicht es, auf der gewünschten Seite eine Textarea (:PX_UPLOAD) anzulegen, die groß genug ist, um die CSV-Dateien per Copy&Paste aufzunehmen. Anschließend startet ein Klick auf einen zuvor angelegten Button folgenden PageProcess:
import_csv(:PX_UPLOAD)
Die Procedure nimmt den Inhalt der Textarea entgegen und geht Zeile für Zeile durch den Inhalt und spaltet diesen mit der Funktion wwv_flow_utilities.string_to_table in ein Array auf. Nach ein paar Plausibilitätsabfragen werden die Daten in eine Tabelle importiert und stehen jetzt für weitere Schritte zur Verfügung.
In der Procedure könnten noch Formatierungen für bestimmte Spalten vorgenommen, oder nicht erwünschte Spalten „ausgeblendet“ werden.
Hi,
gibt es einen besonderen Grund warum Du EXECUTE IMMEDIATE verwendest um das Insert durchzufuehren? Wuerde ein Native Insert nicht genausogut und schneller funktionieren?
Lg
Patrick
Da kommt der „Anfänger“ in mir durch. Die Infos für die Procudure habe ich mir zusammengesammelt. Danke für den Tipp, ich werde ihn mal ausprobieren.
Hi,
auf der Suche nach einer Möglichkeit eine Textdatei mittels APEX in eine Oracle Tabeller einzulesen bin ich auf das obige Script gestossen. Ich habe versucht es dahingehend umzuformen, erhalte jedoch bereits beim Anlegen der Seitenprozedur eien Fehler (ORA-06550 Fand das Symbol „PROCEDURE“ als eines der folgenden erwartet wurde: begin, case…
was mache ich falsch und geht das was ich will überhaupt?
Meinst du Seitenprodezur, oder nicht eher Seitenprozess? Welchen Typ hast du ausgewählt? Wie sieht dein geänderter Code aus?
Es steht „Seitenprozess“ drüber (Seitenbearbeitung –> Seitenprozesse). Ich habe inzwischen „Procedure“ durch „Declare“ ersetzt, nun läuft es drüber aber weiter unten kommt nun der Fehler (ORA-06550 Fand das Symbol “Exception†als eines der folgenden erwartet wurde: avg, current … usw.)
Momentan sieht es so aus, ich habe immer nur eine komplette Zeile einzulesen, das aber in Mengen:
Declare
v_my_array wwv_flow_global.vc_arr2;
empty_array wwv_flow_global.vc_arr2;
v_array wwv_flow_global.vc_arr2;
v_upload VARCHAR2 (32000) := NULL;
v_line VARCHAR2 (32000) := NULL;
bad_values EXCEPTION;
BEGIN
v_upload := REPLACE (p_upload, CHR (09), ‚:‘);
WHILE v_upload IS NOT NULL
LOOP
v_line := SUBSTR (v_upload, 1, INSTR (v_upload, CHR (10)) – 1);
v_my_array := wwv_flow_utilities.string_to_table (v_line);
IF v_my_array.COUNT != 1 — hat die csv-datei die gewünschte Anzahl Spalten?
THEN
RAISE bad_values;
ELSE
v_array := empty_array;
BEGIN
EXECUTE IMMEDIATE ‚INSERT INTO easyleitung(LtgNummer) values (:1)‘
USING
v_my_array (1),
EXCEPTION
WHEN OTHERS
THEN
dbms_output.put_line(‚Fehler‘);
END;
v_upload := SUBSTR (v_upload, INSTR (v_upload, CHR (10)) + 1);
END IF;
END LOOP;
END import_csv;
Hallo Alterron,
hab nicht genau aufgepasst. Lies dir den Beitrag nochmal durch. Die Procedure wird als selbige in der Datenbank abgelegt und aus Apex heraus mit einem Seitenprocess aufgerufen.
Ah, ok, ich habe das falsch aufgefasst und wollte sie in der Anwendung platzieren.
aber wenn ich schon mal hier bin, unerfahren wie ich bin:
Ich möchte die Prozedur nun im SQL-Developer anlegen, vergebe den Namen (import_csv), klicke auf den Reiter DDL und erhalte bereits vorformuliert:
Create
Procedure import_csv as
begin
null;
end import_csv;/
setze ich nun den Code nach create ein ? und wo weise ich dem Button die Prozedur zu ? Kann ich das Ganze auch mit einem „Filepicker“ Element koppeln?
sorry für die vielen Fragen 🙂
Schreib die Procedure in den SQL Developer und direkt davor noch folgendes:
„create or replace procedure import_csv (p_upload IN VARCHAR2)
IS…“
Dann wird die Procedure angelegt, bzw. entsprechend geändert. So kannst du dann immer verfahren.
Der Button führt dann einen Submit der Seite aus und diese Seite hat einen Process (on Submit), der den Inhalt des Textfeldes an die Procedure weitergibt. In dem Beitrag ist der Aufruf beschrieben.
Bestimmt geht das auch mit einem Filepicker. Schau mal auf http://www.oracle.com/technology/products/database/application_express/packaged_apps/packaged_apps.html#CUST nach. Dort findest du sehr gute Beispiel, bei denen du viel lernen kannst.
Vielen Dank für die Hilfe, das Anlegen der Prozedur hat nun schon mal funktioniert.
Die Seite auf oracle.com kenne ich natürlich, habe aber noch nicht das rechte gefunden.
Ich denke ich lege mal einen Thread im forum an, evtl hatte jemand ja schon mal ähnliche Ansprüche. Es ist m.E. aussergwöhnlich schwierig eine einfache Textdatei in eine Tabelle zu bekommen.
Gäbe es eigentlich eine Möglichkeit Apex mit sqlldr zu verheiraten ?
Schau dir mal folgenden Beitrag an:
http://www.cc13.com/wordpress_21/?p=261
Dort ist ein Fileupload für Bilder beschrieben. Ähnlich läuft es auch mit Textdateien. Nur musst du dir noch überlegen, in welchen Datentyp du sie ablegen möchtest. Sicher willst du darin dann suchen können.
Nein suchen muss ich darin nicht, ich muss sie nur in einer Tabelle darstellen bzw verknüpft mit Werten aus einer Tabelle darstellen.
Es geht letztlich nur um die Ansicht und Verknüpfung der Tabellen.
Mir fehlt gerade die Verbindung der Elemente (Dateipicker, Textfeld, Button) untereinander und wie der Button zu „seiner“ Prozedur kommt ist mir doch noch nicht klar 🙁
Der Button selbst löst nur den Submit-Process der Seite aus. Also normales HTML.
Auf der Seite selber ist dann ein Process, der immer startet, wenn der Button gedrückt wurde, bzw. ein Submit der Seite stattfand. Das kannst du bei den Conditions des Processes auswählen.
Servus Carsten,
Dein Beispiel funktioniert astrein! Vielen Dank dafür!
Frage: wie stelle ich es an unterschiedliche Dtentypen in eine vorhandene Tabelle (my_table) zu importieren?
Ein varchar2 in number umzuwandeln
SELECT SUM(to_number(feld3))
FROM MY_TABLE ;
wird mir mit dem Fehler : ORA-01722: Ungültige Zahl Quittiert.
Gruß
MacJo
Da ich deine Ausgangsdaten nicht kenne, könnte ich mir vorstellen, dass das to_number und das SUM zu viel sind. Teil das mal auf und probiere wieder.
Guten Morgen Carsten,
in feld 3 füge ich Stunden ein -> Also Eigentlich Datentyp NUMBER.
in Deinem Beispiel wird VARCHAR2 eingefügt.
Allein die Abfrage
SELECT TO_NUMBER(HOURS)
FROM MY_TABLE;
erzeugt den genannten Fehler.
Wenn ich den Datentyp in MY_TABLE feld3 in NUMBER ändere, wird nichts eingefügt.
Gruß
Servus Carsten,
meine Lösung des Problems sieht wie folgt aus:
Beim Einfügen in die Tabelle werden die Hours mit
…
USING
V_MY_ARRAY (1),
V_MY_ARRAY (2),
-> TO_BINARY_DOUBLE(V_MY_ARRAY (3));
….
in eine numerische Spalte eingefügt.
Viele Grüße
MacJo
Moin Moin,
entschuldigt für die frage an alle (bin absoluter anfänger) aber wo muss ich die procedure genau einfügen?
Die Procedure legst du direkt in deiner Datenbank an.