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.