2012-08-12 82 views
1

我有2個表 - studentstudLoad都有2個字段studIDstudName。我想從student表中加載數據到stuLoad表。 如果數據已經存在於studLoad表中,則應該更新它,否則應該插入它。以下是我的代碼這樣做:在oracle中使用遊標插入和更新記錄

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中執行相同的操作?如果是的話,請讓我知道一樣。

+0

的可能重複的[甲骨文:如何UPSERT(?更新或插入到一個表)](http://stackoverflow.com/questions/237327/oracle-how-to-upsert-update-or-插入表格) – Ben 2012-08-12 12:03:23

+0

你的代碼工作不正常,因爲它沒有在做你正在談論的內容。我很驚訝爲什麼它不會拋出異常。在不匹配記錄的情況下爲NO_DATA_FOUND異常。 IF條件來評估是否插入記錄是錯誤的,因爲它只會插入新的重複項。如果studId在studLoad和學生表中都是唯一的,那麼Ben建議的解決方案可以正常工作。 – 2012-08-12 13:47:35

回答

11

這是一種非常低效的方法。您可以使用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(表中的唯一地址)進行更新。

它聲明瞭一種類型,您一次可以批量放置數據的行數爲10,000行。然後分別處理這些行。

但是,正如我所說這不會像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; 
/
+0

爲了限制更改的次數(因此減少了撤消空間,重做日誌和執行時間),我建議在兩個merge語句(「where l.studName = s.studName」)中的更新中爲new_studName!= old_studName添加條件。 http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_9016.htm#i2081030)和PL/SQL塊(可以用不同方式完成,最好的方法是添加「a .studName!= b.studName「條件在遊標的外部連接子句中)。 – 2012-08-12 13:59:56

+0

感謝隊友...合併解決方案爲我工作! – z22 2012-08-12 17:45:39

+0

@AlessandroRossi,你當然是對的。我已經更新了它。 – Ben 2012-08-12 17:51:01

相關問題