APEX: CSV-Import für den Anwender

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.

Dieser Beitrag wurde unter APEX, Oracle abgelegt und mit , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

18 Antworten zu APEX: CSV-Import für den Anwender

  1. Patrick Wolf sagt:

    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. cc13 sagt:

    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. alterron sagt:

    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. cc13 sagt:

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

  5. alterron sagt:

    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. cc13 sagt:

    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. alterron sagt:

    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. cc13 sagt:

    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. alterron sagt:

    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. cc13 sagt:

    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. alterron sagt:

    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. cc13 sagt:

    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.

  13. MacJo sagt:

    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

  14. cc13 sagt:

    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.

  15. MacJo sagt:

    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ß

  16. MacJo sagt:

    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

  17. Dieter sagt:

    Moin Moin,

    entschuldigt für die frage an alle (bin absoluter anfänger) aber wo muss ich die procedure genau einfügen?

  18. cc13 sagt:

    Die Procedure legst du direkt in deiner Datenbank an.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert