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?