Вставить и обновить запись с помощью курсоров в оракуле
У меня есть 2 таблицы student
а также studLoad
оба имеют 2 поля studID
а также studName
, Я хочу загрузить данные из student
стол в stuLoad
Таблица. Если данные уже существуют в studLoad
таблица, то она должна быть обновлена, иначе она должна быть вставлена. Вот мой код для этого:
create or replace procedure studentLoad is
v_id student.studID%type;
v_name student.studName%type;
v_sn studLoad.studName%type;
cursor cur_load is
select * from student;
begin
open cur_load;
loop
fetch cur_load into v_id,v_name;
exit when cur_load%notfound;
select studName into v_sn from studLoad where studID = v_id;
if(v_sn!= v_name) then
update studLoad set studName= v_name where studID= v_id;
else
insert into studLoad values(v_id,v_name);
dbms_output.put_line(v_id || ' ' || v_name);
end if;
end loop;
close cur_load;
end;
Это не работает. строки в таблице studLoad не обновляются. Как мне это решить? В SQL-сервере мы используем IF EXISTS(select...from stuLoad..)
проверить, существует ли запись в таблице, есть ли способ сделать то же самое в Oracle? Если да, пожалуйста, дайте мне знать то же самое.
2 ответа
Это крайне неэффективный способ сделать это. Вы можете использовать merge
оператор, а затем нет необходимости в курсорах, цикле или (если вы можете обойтись без) PL/SQL.
MERGE INTO studLoad l
USING ( SELECT studId, studName FROM student ) s
ON (l.studId = s.studId)
WHEN MATCHED THEN
UPDATE SET l.studName = s.studName
WHERE l.studName != s.studName
WHEN NOT MATCHED THEN
INSERT (l.studID, l.studName)
VALUES (s.studId, s.studName)
Убедись, что ты commit
после завершения, чтобы иметь возможность увидеть это в базе данных.
Чтобы на самом деле ответить на ваш вопрос, я бы сделал это примерно так: Это дает преимущество выполнения большей части работы в SQL и обновления только на основе rowid, уникального адреса в таблице.
Он объявляет тип, в который вы помещаете данные оптом, по 10000 строк за раз. Затем обрабатывает эти строки индивидуально.
Однако, как я уже сказал, это будет не так эффективно, как merge
,
declare
cursor c_data is
select b.rowid as rid, a.studId, a.studName
from student a
left outer join studLoad b
on a.studId = b.studId
and a.studName <> b.studName
;
type t__data is table of c_data%rowtype index by binary_integer;
t_data t__data;
begin
open c_data;
loop
fetch c_data bulk collect into t_data limit 10000;
exit when t_data.count = 0;
for idx in t_data.first .. t_data.last loop
if t_data(idx).rid is null then
insert into studLoad (studId, studName)
values (t_data(idx).studId, t_data(idx).studName);
else
update studLoad
set studName = t_data(idx).studName
where rowid = t_data(idx).rid
;
end if;
end loop;
end loop;
close c_data;
end;
/
Если вы хотите использовать свою процедуру, подумайте об изменении некоторых строк:
create or replace procedure studentLoad is
v_id student.studID%type;
v_name student.studName%type;
v_sn studLoad.studName%type;
cursor cur_load is
select * from student;
begin
open cur_load;
loop
fetch cur_load into v_id,v_name;
exit when cur_load%notfound;
begin
select studName into v_sn from studLoad where studID = v_id;
if(v_sn!= v_name) then
update studLoad set studName= v_name where studID= v_id;
end if;
exception
when no_data_found then
insert into studLoad values(v_id,v_name);
end;
dbms_output.put_line(v_id || ' ' || v_name);
end loop;
close cur_load;
end;
Думаю должно работать, не тестировал.