prog:apex_datei_parser_laden
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende Überarbeitung | |||
prog:apex_datei_parser_laden [2019/11/08 15:09] – [Bericht anlegen mit apex_data_parser.parse] gpipperr | prog:apex_datei_parser_laden [2019/11/14 11:51] (aktuell) – [Daten laden mit apex_data_parser.parse] gpipperr | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ===== Oracle APEX 19.2 - APEX_DATA_PARSER für das Laden von Excel und CSV Datein einsetzen ===== | ||
+ | |||
+ | <fc # | ||
+ | |||
+ | Eine Datei, möglichst natives Excel, soll in eine Tabelle in der Datenbank geladen werden. | ||
+ | |||
+ | Vor 19.1 war zwar schon ein Data Load Wizard in APEX implementiert, | ||
+ | |||
+ | In einer 5 APEX Umgebung daher mit eigenen Mitteln diese Aufgaben umständlich umgesetzt. | ||
+ | |||
+ | * Daten in die DB über APEX laden => [[prog: | ||
+ | |||
+ | * Daten wieder auslesen => [[prog: | ||
+ | |||
+ | |||
+ | <fc # | ||
+ | |||
+ | |||
+ | Ab 19.1 kann mit dem APEX APEX_DATA_PARSER das ganze viel einfacher und vor allem auch ohne Plugins für natives Excel umgesetzt werden. | ||
+ | |||
+ | |||
+ | => API => https:// | ||
+ | |||
+ | |||
+ | |||
+ | Hierzu nun ein paar Anmerkungen mit den wichtigsten SQL Statements für diese Aufgabe. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Ablauf ==== | ||
+ | |||
+ | |||
+ | * Formular um eine CSV / Excel Datei in eine Tabelle zu laden | ||
+ | * Den Inhalt der Datei nach dem Laden auf der Seite anzeigen | ||
+ | * Laden der Daten aus der Datei in die passende Datenbank Tabelle | ||
+ | * Anzeige der erfolgreich geladenen Daten und der fehlerhaften Daten | ||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Laden der Datei in eine eigene Stage Tabelle ==== | ||
+ | |||
+ | |||
+ | Die Stage Tabelle ist in diesem Projekt fachlich notwendig um die Dateien gleichzeitig zu archivieren. | ||
+ | |||
+ | Alternativ kann natürlich einfach die Datei per Standard APEX Verhalten in die APEX_APPLICATION_TEMP_FILES geladen und dann vor dort ausgelesen werden. | ||
+ | |||
+ | |||
+ | === Stage Tabelle in der DB anlegen === | ||
+ | |||
+ | |||
+ | Eine paassende Tabelle für den Datei Upload in der Datenbank anlegen, wie: | ||
+ | |||
+ | <code sql> | ||
+ | |||
+ | create table T_IMPORT_FILES | ||
+ | ( | ||
+ | DDE_SK | ||
+ | , NAME | ||
+ | , FILENAME | ||
+ | , MIME_TYPE | ||
+ | , CREATED_ON | ||
+ | , BLOB_CONTENT | ||
+ | -- | ||
+ | , SETTINGS_DEF_BY_USER | ||
+ | , CREATED_AT | ||
+ | , SETTINGS_CHAN_BY_USER | ||
+ | , EDIT_AT | ||
+ | , CONSTRAINT T_KDE_EXCLUDE_IMPORT_PK PRIMARY KEY ( | ||
+ | DDE_SK | ||
+ | ) | ||
+ | ENABLE | ||
+ | ) | ||
+ | </ | ||
+ | |||
+ | |||
+ | In APEX | ||
+ | |||
+ | |||
+ | === APEX Maske zum Laden der Daten === | ||
+ | |||
+ | |||
+ | * In APEX ein ITEM vom Typ "File Browser" | ||
+ | * Es kann auch gleich die passende Tabelle hier angeben werden, dann kann ein eigener Prozess da für entfallen. | ||
+ | * Button um den Lade Prozess zu starten | ||
+ | |||
+ | Hier ein Beispiel für ein Prozess um Datei in eigene Temporäre Tabelle laden, falls mehr Logik notwendig ist als der APEX Default liefert: | ||
+ | |||
+ | <code plsql> | ||
+ | |||
+ | declare | ||
+ | |||
+ | v_file_count pls_integer: | ||
+ | |||
+ | v_file blob; | ||
+ | |||
+ | v_message varchar2(4000): | ||
+ | |||
+ | v_filename varchar2(512); | ||
+ | |||
+ | v_id number; | ||
+ | | ||
+ | begin | ||
+ | if : | ||
+ | | ||
+ | --- Put your own logic in here | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | select count(ID) into v_file_count | ||
+ | from apex_application_temp_files | ||
+ | where name = v_filename; | ||
+ | |||
+ | if v_file_count > 0 then | ||
+ | for rec in (select | ||
+ | id, | ||
+ | application_id, | ||
+ | name, | ||
+ | filename, | ||
+ | mime_type, | ||
+ | created_on, | ||
+ | blob_content | ||
+ | from apex_application_temp_files where name = v_filename ) loop | ||
+ | |||
+ | v_message:= v_message||' | ||
+ | | ||
+ | DDE_SK | ||
+ | , NAME | ||
+ | , FILENAME | ||
+ | , MIME_TYPE | ||
+ | , CREATED_ON | ||
+ | , BLOB_CONTENT | ||
+ | , SETTINGS_DEF_BY_USER | ||
+ | , CREATED_AT | ||
+ | | ||
+ | values ( T_IMPORT_FILE_seq.nextval -- DDE_SK | ||
+ | , rec.NAME | ||
+ | , rec.FILENAME | ||
+ | , rec.mime_type | ||
+ | , rec.CREATED_ON | ||
+ | , rec.blob_content | ||
+ | , : | ||
+ | , systimestamp) | ||
+ | RETURNING DDE_SK INTO v_id; | ||
+ | end loop; | ||
+ | | ||
+ | -- clean the tempfile | ||
+ | begin | ||
+ | delete apex_application_temp_files | ||
+ | commit; | ||
+ | EXCEPTION | ||
+ | when others then | ||
+ | | ||
+ | end; | ||
+ | end if; | ||
+ | end if; | ||
+ | | ||
+ | apex_application.g_print_success_message := '< | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | ==== Daten mit dem Parser auslesen ===== | ||
+ | |||
+ | Eine Report auf der Seite anlegen und mit Hilfe von **apex_data_parser.parse** die Datei parsen und anzeigen. | ||
+ | |||
+ | === Das passende Sheet aus der Excel Datei auslesen mit apex_data_parser.get_xlsx_worksheets === | ||
+ | |||
+ | In Excel kann sogar das einzelne Sheet selektiert werden aus dem die Daten geladen werden sollen! | ||
+ | |||
+ | <code sql> | ||
+ | select sheet_display_name, | ||
+ | from T_IMPORT_FILES f, | ||
+ | | ||
+ | where f.name = : | ||
+ | </ | ||
+ | |||
+ | |||
+ | === Bericht anlegen mit apex_data_parser.parse === | ||
+ | |||
+ | SQL für den Report | ||
+ | |||
+ | <code sql> | ||
+ | |||
+ | select | ||
+ | , col001 | ||
+ | , col002 | ||
+ | , col003 | ||
+ | , col004 | ||
+ | , col005 | ||
+ | , col006 | ||
+ | -- .. up to 300 columns can be selected | ||
+ | , col300 | ||
+ | |||
+ | from T_IMPORT_FILES f, | ||
+ | | ||
+ | p_content | ||
+ | p_add_headers_row | ||
+ | p_xlsx_sheet_name | ||
+ | p_max_rows | ||
+ | p_store_profile_to_collection => ' | ||
+ | p_file_name | ||
+ | where f.name = nvl(: | ||
+ | and line_number > 1 | ||
+ | </ | ||
+ | |||
+ | Beispiel für eine reine CSV Datei: | ||
+ | |||
+ | <code sql> | ||
+ | SELECT col001 | ||
+ | , col002 | ||
+ | , col003 | ||
+ | , col004 | ||
+ | FROM apex_application_temp_files f, | ||
+ | | ||
+ | p_content | ||
+ | p_add_headers_row | ||
+ | p_csv_col_delimiter | ||
+ | p_file_name | ||
+ | ) | ||
+ | ) p | ||
+ | WHERE f.name = : | ||
+ | |||
+ | </ | ||
+ | |||
+ | Die Dateiendung ist wichtig für den Parser! | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | === Daten aus der Datei in die Zieltabelle laden === | ||
+ | |||
+ | |||
+ | == Error Log == | ||
+ | |||
+ | Error Log zuvor auf der Ziel-Tabelle anlegen um Fehler mitschreiben zu können. | ||
+ | |||
+ | <code sql> | ||
+ | -- +====================================================+ | ||
+ | -- Error Log table | ||
+ | |||
+ | BEGIN | ||
+ | DBMS_ERRLOG.create_error_log (dml_table_name => ' | ||
+ | END; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | === Daten laden mit apex_data_parser.parse === | ||
+ | |||
+ | Prozess für den Übertrag in die Zieltabelle: | ||
+ | <code sql> | ||
+ | |||
+ | declare | ||
+ | v_error_log_exists boolean := false; | ||
+ | v_message varchar2(4000): | ||
+ | begin | ||
+ | | ||
+ | delete from ERR$_T_CSV_DETAILS where ORA_ERR_TAG$ like : | ||
+ | commit; | ||
+ | | ||
+ | | ||
+ | | ||
+ | insert into T_CSV_DETAILS ( | ||
+ | DDE_SK | ||
+ | , KUNDENNUMMER | ||
+ | , KUNDENNUMMER_2 | ||
+ | , INSTITUTSZUORDNUNG | ||
+ | , CASENUMBER | ||
+ | , TRIGGER_TYPE | ||
+ | , INSERT_AT | ||
+ | , INSERT_REASON | ||
+ | , IS_ACTIVE | ||
+ | ) select | ||
+ | , col002 as KUNDENNUMMER | ||
+ | , col003 as KUNDENNUMMER_2 | ||
+ | , col001 as INSTITUTSZUORDNUNG | ||
+ | , col002as CASENUMBER | ||
+ | , col006 as TRIGGER_TYPE | ||
+ | , to_date(col005,' | ||
+ | , col007 as INSERT_REASON | ||
+ | , ' | ||
+ | from T_IMPORT_FILES f, | ||
+ | | ||
+ | p_content | ||
+ | p_add_headers_row | ||
+ | p_xlsx_sheet_name | ||
+ | p_max_rows | ||
+ | p_store_profile_to_collection => ' | ||
+ | p_file_name | ||
+ | where f.name = : | ||
+ | and line_number > 1 -- not the first line of the dokument! | ||
+ | log errors into ERR$_T_CSV_DETAILS ( :APP_USER|| ' - ' ||' von ' || to_char(sysdate,' | ||
+ | reject limit unlimited; | ||
+ | |||
+ | : | ||
+ | |||
+ | | ||
+ | into : | ||
+ | from ERR$_T_CSV_DETAILS where ORA_ERR_TAG$ like : | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | | ||
+ | end; | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | Beispiel für das Laden einer reinen CSV Datei: | ||
+ | |||
+ | <code sql> | ||
+ | declare | ||
+ | v_message varchar2(4000): | ||
+ | begin | ||
+ | | ||
+ | delete from ERR$_BMA_MODBUS where ORA_ERR_TAG$ like : | ||
+ | commit; | ||
+ | |||
+ | merge into BMA_MODBUS m | ||
+ | using ( select | ||
+ | | ||
+ | , col002 as NUMMER | ||
+ | , col003 as SUB_NUMMER | ||
+ | , col004 as register | ||
+ | FROM apex_application_temp_files f, | ||
+ | | ||
+ | p_content | ||
+ | p_add_headers_row | ||
+ | p_csv_col_delimiter | ||
+ | p_file_name | ||
+ | ) p | ||
+ | WHERE f.name = : | ||
+ | | ||
+ | on ( i.TYP=m.typ and i.NUMMER=m.NUMMER and nvl(i.SUB_NUMMER, | ||
+ | WHEN matched | ||
+ | THEN | ||
+ | update set m.register=i.register | ||
+ | WHEN NOT matched | ||
+ | THEN | ||
+ | | ||
+ | , TYP | ||
+ | , NUMMER | ||
+ | , SUB_NUMMER | ||
+ | , REGISTER | ||
+ | ) values ( | ||
+ | BMA_MODBUS_seq.nextval | ||
+ | , i.TYP | ||
+ | , i.NUMMER | ||
+ | , i.SUB_NUMMER | ||
+ | , i.register | ||
+ | ) | ||
+ | log errors into ERR$_BMA_MODBUS ( :APP_USER|| ' - ' ||' von ' || to_char(sysdate,' | ||
+ | reject limit unlimited; | ||
+ | |||
+ | : | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | into : | ||
+ | from ERR$_BMA_MODBUS where ORA_ERR_TAG$ like : | ||
+ | |||
+ | | ||
+ | |||
+ | : | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | end; | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | ==== Quellen ==== | ||
+ | |||
+ | Carsten Czarski | ||
+ | |||
+ | |||
+ | * https:// | ||
+ | * https:// | ||
+ | |||
+ | Web: | ||
+ | |||
+ | |||
+ | * https:// | ||
+ | * https:// |
prog/apex_datei_parser_laden.txt · Zuletzt geändert: 2019/11/14 11:51 von gpipperr