Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Faisal .

Asked: May 28, 2005 - 3:55 pm UTC

Last updated: May 29, 2005 - 3:04 pm UTC

Version: 10g

Viewed 10K+ times! This question is

You Asked

Hi Tom,

I want to use merge command in loop. In a USING clause, how could I reference cursor or record type instead of table.

For Example

declare
cursor c1 is select * from emp;

begin
for emp_rec in c1 loop

MERGE INTO newemp n1
USING emp_rec e1 <---- How could I use cursor or record type
ON ( n1.empno = e1.empno )
WHEN MATCHED THEN UPDATE
SET n1.empno = e1.empno,
n1.ename = e1.ename,
WHEN NOT MATCHED THEN
INSERT ( empno, ename)
values ( e1.empno,
e1.ename);
end loop;
end;

Thanks in advance...



and Tom said...

I would recommend if you are going slow by slow to use

update emp set ....
if sql%rowcount = 0
the
insert emp;
end if;


Less code, more efficient (else we need to select from dual). However, if you want to do this in bulk (even more efficient than slow by slow), you would do this:

ops$tkyte@ORA10G> create table emp as select empno, ename from scott.emp;

Table created.

ops$tkyte@ORA10G> create table new_emp as select empno, ename from scott.emp where mod(empno,2)=0;

Table created.

ops$tkyte@ORA10G>
ops$tkyte@ORA10G> create or replace type myScalarType as object
2 ( empno number, ename varchar2(30) )
3 /

Type created.

ops$tkyte@ORA10G> create or replace type myTableType as table of myScalarType
2 /

Type created.

ops$tkyte@ORA10G>
ops$tkyte@ORA10G>
ops$tkyte@ORA10G> declare
2 l_data myTableType;
3 l_limit number default 10;
4
5 cursor c is select myScalarType(empno,ename) from emp;
6 begin
7 open c;
8 loop
9 fetch c bulk collect into l_data limit l_limit;
10 if ( l_data.count > 0 )
11 then
12 for i in 1 .. l_data.count
13 loop
14 l_data(i).ename := initcap( l_data(i).ename );
15 end loop;
16 merge into new_emp
17 using ( select * from table(cast(l_data as myTableType))) X
18 on (new_emp.empno = x.empno)
19 when matched then update set ename = x.ename
20 when not matched then insert ( empno, ename ) values ( x.empno, x.ename );
21 end if;
22 exit when c%notfound;
23 end loop;
24 end;
25 /

PL/SQL procedure successfully completed.


Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks

Faisal, May 29, 2005 - 12:25 pm UTC

Thanks Tom, this is exactly I was looking for, I will use bulk collect, but do I have to define column by column in the statement below or I can define record type.

create or replace type myScalarType as object
( empno number, ename varchar2(30)) <-- I have more then 100 columns here

Thanks again

Tom Kyte
May 29, 2005 - 1:01 pm UTC

object types are not PLSQL record types, there is no "create type x as record of table" or anything.

But bear in mind, with more than 100 columns -- you MERGE is going to have to reference them by name anyhow.

To reduce the potential for error, I'd be tempted to use a plsql routine to create this type from the data dictionary. If the underlying schema changes, it can be used to regenerate the correct type.

Another option?

Bob B, May 29, 2005 - 12:54 pm UTC

I'm taking a wild guess here, but it seems like the purpose of the procedure is to pass in a result set containing valid data (employees in the example) and to merge them into existing table data (all employees in the example). This sounds like a good place to bulk insert into a GTT and then merge the GTT into the table. Something like:

1) Open cursor
2) Bulk collect cursor into plsql table
3) Bulk insert plsql table into GTT
4) Merge GTT into destination table
5) Close cursor

Steps 3 and 4 could be put into their own procedure as a means to merge a plsql table into the destination table.

I'll post an example when I have access to Oracle again =/ (Tue)


Tom Kyte
May 29, 2005 - 1:03 pm UTC

sure, the example would be to bulk collect, process, bulk insert and then merge.

But, if you are going to bulk insert and spend cycles doing that, might just as well merge in the first place? seems to be cutting out of step this way rather than adding one.

(I cannot imagine life without access to the database! I'm at home and I have at least 10 instances running -- well, 12 if you count the RAC database I just turned on to look at something.... and access to dozens more at work if needed :)



What is GTT?

Faisal, May 29, 2005 - 1:22 pm UTC

Tom thanks for quick response, I got your point.

Bob: What is GTT means?

Tom Kyte
May 29, 2005 - 3:04 pm UTC

Global
Temporary
Table

gtt = global temporary table

Matthias Rogel, May 29, 2005 - 3:05 pm UTC


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library