Skip to Main Content

APEX

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

File browse/upload with update table

DooliusMar 10 2014 — edited Mar 11 2014


I've searched many forums on here about uploading .cvs files into tables and have ran across the example from Vikas about the file upload (with creating a table) and i've also ran across another example (I believe by JMcG) uploads the data into an existing table.

Both examples have worked correctly for me, however, they do not do what I would like them to do.

Basically, my user will download a spreadsheet from a tabular form with empty cells where there is no data. They will then put data into the empty cells and I am wondering how to edit the two examples above (code/link provided below for the JMcG upload to existing table) so that when my user uploads the file it updates the correct information in my table instaed of just making a new row.

code that I need to execute:

UPDATE table_name

SET table_col2 = csv_col2, table_col3 = csv_col3, ......... table_colN = csv_colN

where table_PK = csv_col1

create or replace PACKAGE BODY htmldb_tools

AS

    TYPE varchar2_t IS TABLE OF VARCHAR2(32767) INDEX BY binary_integer;

    -- Private functions --{{{

    PROCEDURE delete_collection ( --{{{

    -- Delete the collection if it exists

        p_collection_name IN VARCHAR2

    )

    IS

    BEGIN

        IF (htmldb_collection.collection_exists(p_collection_name))

        THEN

            htmldb_collection.delete_collection(p_collection_name);

        END IF;

    END delete_collection; --}}} 

    PROCEDURE csv_to_array ( --{{{

    -- Utility to take a CSV string, parse it into a PL/SQL table

    -- Note that it takes care of some elements optionally enclosed

    -- by double-quotes.

        p_csv_string IN  VARCHAR2,

        p_array      OUT wwv_flow_global.vc_arr2,

        p_separator  IN  VARCHAR2        := ','

    )

    IS

        l_start_separator PLS_INTEGER     := 0;

        l_stop_separator  PLS_INTEGER     := 0;

        l_length          PLS_INTEGER     := 0;

        l_idx             BINARY_INTEGER  := 0;

        l_quote_enclosed  BOOLEAN         := FALSE;

        l_offset          PLS_INTEGER     := 1;

    BEGIN

        l_length          := NVL(LENGTH(p_csv_string),0);

        IF (l_length <= 0)

        THEN

            RETURN;

        END IF;

        LOOP

            l_idx := l_idx + 1;

            l_quote_enclosed := FALSE;

            IF SUBSTR(p_csv_string, l_start_separator + 1, 1) = '"'

            THEN

              l_quote_enclosed := TRUE;

              l_offset := 2;

              l_stop_separator := INSTR(p_csv_string, '"', l_start_separator + l_offset, 1);

            ELSE

              l_offset := 1;

              l_stop_separator := INSTR(p_csv_string, p_separator, l_start_separator + l_offset, 1);

            END IF;

            IF l_stop_separator = 0

            THEN

              l_stop_separator := l_length + 1;

            END IF;

            p_array(l_idx) := (SUBSTR(p_csv_string, l_start_separator + l_offset,(l_stop_separator - l_start_separator - l_offset)));

            EXIT WHEN l_stop_separator >= l_length;

            IF l_quote_enclosed

            THEN

              l_stop_separator := l_stop_separator + 1;

            END IF;

            l_start_separator := l_stop_separator;

        END LOOP;

    END csv_to_array; --}}}

    PROCEDURE get_records(p_blob IN blob,p_records OUT varchar2_t) --{{{

    IS

       l_record_separator VARCHAR2(2) := chr(13)||chr(10);

       l_last             INTEGER;

       l_current          INTEGER;

    BEGIN

        -- Sigh, stupid DOS/Unix newline stuff. If HTMLDB has generated the file,

        -- it will be a Unix text file. If user has manually created the file, it

        -- will have DOS newlines.

        -- If the file has a DOS newline (cr+lf), use that

        -- If the file does not have a DOS newline, use a Unix newline (lf)

        IF (NVL(dbms_lob.instr(p_blob,utl_raw.cast_to_raw(l_record_separator),1,1),0)=0)

        THEN

            l_record_separator := chr(10);

        END IF;

        l_last := 1;

        LOOP

            l_current := dbms_lob.instr( p_blob, utl_raw.cast_to_raw(l_record_separator), l_last, 1 );

            EXIT WHEN (nvl(l_current,0) = 0);

            p_records(p_records.count+1) := utl_raw.cast_to_varchar2(dbms_lob.substr(p_blob,l_current-l_last,l_last));

            l_last := l_current+length(l_record_separator);

        END LOOP;

    END get_records; --}}}

    --}}}

    -- Utility functions --{{{

    PROCEDURE parse_textarea ( --{{{

        p_textarea        IN VARCHAR2,

        p_collection_name IN VARCHAR2

    )

    IS

        l_index   INTEGER;

        l_string  VARCHAR2(32767) := TRANSLATE(p_textarea,chr(10)||chr(13)||' ,','@@@@');

        l_element VARCHAR2(100);

    BEGIN

        l_string := l_string||'@';

        htmldb_collection.create_or_truncate_collection(p_collection_name);

        LOOP

            l_index := instr(l_string,'@');

            EXIT WHEN NVL(l_index,0)=0;

            l_element := substr(l_string,1,l_index-1);

            IF (trim(l_element) IS NOT NULL)

            THEN

                htmldb_collection.add_member(p_collection_name,l_element);

            END IF;

            l_string := substr(l_string,l_index+1);

        END LOOP;

    END parse_textarea; --}}} 

   

    PROCEDURE parse_file( --{{{

        p_file_name       IN VARCHAR2,

        p_collection_name IN VARCHAR2,

        p_headings_item   IN VARCHAR2,

        p_columns_item    IN VARCHAR2,

        p_ddl_item        IN VARCHAR2,

        p_table_name      IN VARCHAR2 DEFAULT NULL

    )

    IS

       l_blob        blob;

       l_records     varchar2_t;

       l_record      wwv_flow_global.vc_arr2;

       l_datatypes   wwv_flow_global.vc_arr2;

       l_headings    VARCHAR2(4000);

       l_columns     VARCHAR2(4000);

       l_seq_id      NUMBER;

       l_num_columns INTEGER;

       l_ddl         VARCHAR2(4000);

    BEGIN

        IF (p_table_name is not null)

        THEN

         /*

          BEGIN

            execute immediate 'drop table '||p_table_name;

          EXCEPTION 

            WHEN OTHERS THEN NULL;

          END;

         

          l_ddl := 'create table '||p_table_name||' '||v(p_ddl_item);

          htmldb_util.set_session_state('P149_DEBUG',l_ddl);

          execute immediate l_ddl;

          */

          --My PL/SQL APEX knowledge is not that great right now, but I believe in order to accomplish this task, the below "insert into" statement is what

             needs to be changed.

          l_ddl := 'insert into '||p_table_name||' '||

                   'select '||v(p_columns_item)||' '||

                   'from htmldb_collections '||

                   'where seq_id > 0 and collection_name='''||p_collection_name||'''';

          htmldb_util.set_session_state('P149_DEBUG',v('P149_DEBUG')||'/'||l_ddl);

          execute immediate l_ddl;

          RETURN;

        END IF;

            

        BEGIN

            select blob_content into l_blob from wwv_flow_files

            where name=p_file_name;

        EXCEPTION

          WHEN NO_DATA_FOUND THEN

              raise_application_error(-20000,'File not found, id='||p_file_name);

        END;

       

        get_records(l_blob,l_records);

        IF (l_records.count < 2)

        THEN

            raise_application_error(-20000,'File must have at least 3 ROWS, id='||p_file_name);

        END IF;

        -- Initialize collection

        htmldb_collection.create_or_truncate_collection(p_collection_name);

       

        -- Get column headings and datatypes

        csv_to_array(l_records(1),l_record);

        csv_to_array(l_records(2),l_datatypes);

        l_num_columns := l_record.count;

        if (l_num_columns > 50) then

          raise_application_error(-20000,'Max. of 50 columns allowed, id='||p_file_name);          

        end if;

       

        -- Get column headings and names 

        FOR i IN 1..l_record.count

        LOOP

            l_headings := l_headings||':'||l_record(i);

            l_columns  := l_columns||',c'||lpad(i,3,'0');

        END LOOP;

        l_headings := ltrim(l_headings,':');

        l_columns  := ltrim(l_columns,',');

        htmldb_util.set_session_state(p_headings_item,l_headings);

        htmldb_util.set_session_state(p_columns_item,l_columns);

        /*

        -- Get datatypes

        FOR i IN 1..l_record.count

        LOOP

            l_ddl := l_ddl||','||l_record(i)||' '||l_datatypes(i);

        END LOOP;

        l_ddl := '('||ltrim(l_ddl,',')||')';

        htmldb_util.set_session_state(p_ddl_item,l_ddl);

        */

        -- Save data into specified collection

        FOR i IN 2..l_records.count

        LOOP

            csv_to_array(l_records(i),l_record);

            l_seq_id := htmldb_collection.add_member(p_collection_name,'dummy');

            FOR i IN 1..l_record.count

            LOOP

                htmldb_collection.update_member_attribute(

                    p_collection_name=> p_collection_name,

                    p_seq            => l_seq_id,

                    p_attr_number    => i,

                    p_attr_value     => l_record(i)

                );

            END LOOP;

        END LOOP;

        DELETE FROM wwv_flow_files WHERE name=p_file_name;

   END;

BEGIN

  NULL;

END;

Any and all help is appreciated!

Thanks

Doolius

Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Apr 8 2014
Added on Mar 10 2014
10 comments
1,384 views