APEX: CSV-Import für den Anwender » CC13.com
Mittwoch, Juni 17th, 2009 | Author: cc13

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.

Tags: ,
Category: APEX, Oracle
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

12 Responses

  1. 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

  2. 2
    cc13 

    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.

  3. 3
    alterron 

    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?

  4. 4
    cc13 

    Meinst du Seitenprodezur, oder nicht eher Seitenprozess? Welchen Typ hast du ausgewählt? Wie sieht dein geänderter Code aus?

  5. 5
    alterron 

    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;

  6. 6
    cc13 

    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.

  7. 7
    alterron 

    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 :)

  8. 8
    cc13 

    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.

  9. 9
    alterron 

    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 ?

  10. 10
    cc13 

    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.

  11. 11
    alterron 

    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 :(

  12. 12
    cc13 

    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.

Leave a Reply » Log in