简体   繁体   中英

Oracle 12c - Creating two records out of 1 record in an insert select

I have a insert select query that brings back around 1 million records, each record has around 30 columns, there are two columns (performance total, mechanical total). One of these columns will have a value in them. Performance Total could have nulll value, mechanical total could have null value or both could have values for that record.

When the record has a value in both columns (performance total, mechanical total) I want the SQL query to create two records, so two records are inserted into a table rather than one. One record being the performance record and one a mechanical record. The performance total or mechanical total will be inserted into a table where there's is total field.

How can this be done in an SQL query without creating a UNION statement as it cause performance issues??

I don't suppose this is any more efficient that using a UNION, but you could do this:

insert into target (a, b, c, rec_type, rec_total)
select mt.a, mt.b, mt.c,
       case when r.rec = 1 then 'PERFORMANCE' else 'MECHANICAL' end 
       case when r.rec = 1 then mt.perf_total else mt.mech_total end 
from mytable mt
    cross join (select rownum rec from dual connect by level <= 2) r
where (mt.perf_total is not null and r.rec=1)
or (mt.mech_total is not null and r.rec = 2);

You are describing union all :

select . . . , 'performance' as which, performance_total
from t
where performance_total is not null
union all
select . . . , 'mechanical' as which, mechanical_total
from t
where mechanical_total is not null;

This does require scanning the table twice. I'm not sure if that is such a big hit on a base table with a million rows, which should fit into memory.

If it were (and this would be particularly true if the table were really a view), then I would phrase an unpivot as:

select . . . , pm.which,
       (case when which = 'performance' then performance_total
             else mechanical_total
        end)
from t cross join
     (select 'performance' as which from dual union all
      select 'mechanical' as which from dual 
     ) pm
where (case when which = 'performance' then performance_total
            else mechanical_total
       end) is not null;

Or, in the most recent versions of Oracle, use a lateral join:

select . . . , pm.which, pm.total
from t cross join lateral
     (select 'performance' as which, performance_total as total from dual union all
      select 'mechanical' as which, mechanical_total from dual 
     ) pm
where total is not null;

Just to let you know I used the UNPIVOT on my records in the end it worked a treat.

SELECT TYPE_OF_RECORD, RECORD_POINTS, 28 columns 
FROM ( SELECT PERF_TOTAL, MECH_TOTAL, 28 columns 
       FROM TABLE   UNPIVOT (RECORD_POINTS FOR TYPE_OF_RECORD  IN
                             (PERF_TOTAL AS 'PERF',
                              MECH_TOTAL AS 'MECH'))  
       WHERE RECORD_POINTS > 0
 ) X;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM