Skip to Main Content

SQL & PL/SQL

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!

Merge possible from nested table?

donovan7800Feb 15 2012 — edited Feb 15 2012
I recently have started using the merge command for some of our standard 'upsert' procedures. The old design for inserts was coming from a Java web service that would send over a flat file, which in turn the Java would call an insert procedure n times while in a loop, and on each call the procedure would perform a single insert.

As you are probably already shaking your head, I realize this makes way too many database calls to be scalable and is poor design. So I now have modified the procedure to take a nested table as the input and I loop through the nested table and do all the inserts in a single procedure call. I now want to take advantage of bulk binding. I know there is the FORALL command, but I figured there was a way to do this with MERGE since the procedure does an update if a match is found instead. I didn't know if there is any syntax to do this as the oracle docs state the USING clause can be a table, view or subquery.

I am using Oracle 10gR2 and SQL Developer 3.x. This was my attempt:
CREATE TABLE merge_table
(
    t_id     NUMBER(9,0),
    t_desc   VARCHAR2(100)
);
/

CREATE OR REPLACE TYPE merge_type IS OBJECT
(
    type_id     NUMBER(9,0),
    type_desc   VARCHAR2(100)
);
/

CREATE OR REPLACE TYPE merge_list IS TABLE OF merge_type;
/

CREATE OR REPLACE PROCEDURE my_merge_proc(p_records IN merge_list)
AS
BEGIN

    MERGE INTO merge_table MT
    USING 
    (
        SELECT 
            p_records.type_id, 
            p_records.type_desc
        FROM DUAL
    ) D            
    ON 
    (
        MT.t_id = p_records.type_id 
    )
    
    WHEN MATCHED THEN UPDATE 
    SET 
        t_id   = p_records.type_id,
        t_desc = p_records.type_desc
        
    WHEN NOT MATCHED THEN INSERT
    (            
        t_id,
        t_desc
    ) 
    VALUES
    (
        p_records.type_id,
        p_records.type_desc
    );

END;
/
show error

CLEAR SCREEN
SET SERVEROUTPUT ON

-- test script to execute procedure
DECLARE
    l_list merge_list := merge_list();
    l_size NUMBER(9,0) := 5;

BEGIN
    
    l_list.EXTEND(l_size);
    
    FOR i IN 1 .. l_size
    LOOP
        l_list(i) := merge_type(i,'desc ' || TO_CHAR(i));
    END LOOP;

    my_merge_proc(p_records => l_list);
    
END;
/

PROCEDURE my_merge_proc compiled
Warning: execution completed with warning
10/23          PLS-00302: component 'TYPE_DESC' must be declared
10/13          PL/SQL: ORA-00904: "P_RECORDS"."TYPE_DESC": invalid identifier
5/5            PL/SQL: SQL Statement ignored
I know the syntax isn't correct. How do I fix this or is it even possible to do what I am trying to do?
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Mar 14 2012
Added on Feb 15 2012
4 comments
1,478 views