2015-05-06 45 views
1

我有一個存儲過程,它從多個表中獲取數據,並創建一個只包含我想要的列的新表。我現在想通過嘗試插入/更新至少包含一列新數據的行來提高性能。對於只接收已有數據的現有行,我想跳過該行的更新。合併聲明而不影響數據沒有變化的記錄

例如,如果一個行包含的數據:

ID | date | population | gdp 
15 | 01-JUN-10 | 1,530,000 | $67,000,000,000 

和MERGE語句來爲ID 15日01-JUN-10與人口1,530,000和國內生產總值$六七○○○○○○○○○然後我不想更新行。

下面是我的一些代碼片段:

create or replace PROCEDURE   COUNTRY ( 
    fromDate IN DATE, 
    toDate IN DATE, 
    filterDown IN INT, 
    chunkSize IN INT 
) AS 

--cursor 
cursor cc is 
    select c.id, cd.population_total_count, cd.evaluation_date, cf.gdp_total_dollars 
    from countries c 
    join country_demographics cd on c.id = cd.country_id 
    join country_financials cf on cd.country_id = cf.country_id and cf.evaluation_date = cd.evaluation_date 
    where cd.evaluation_date > fromDate and cd.evaluation_date < toDate 
    order by c.id,cd.evaluation_date; 

--table 
type cc_table is table of cc%rowtype; 
c_table cc_table; 

BEGIN 

    open cc; 
    loop -- cc loop 
    fetch cc bulk collect into c_table limit chunkSize; --limit by chunkSize parameter 

     forall j in 1..c_table.count 
     merge 
      into F_AMB_COUNTRY_INFO_16830 tgt 
      using (
      select c_table(j).id cid, 
        c_table(j).evaluation_date eval_date, 
        c_table(j).population_total_count pop, 
        c_table(j).gdp_total_dollars gdp 
      from dual 
     ) src 
      on (cid = tgt.country_id AND eval_date = tgt.evaluation_date) 
     when matched then 
      update 
      set tgt.population_total_count = pop, 
       tgt.gdp_total_dollars = gdp 
     when not matched then 
      insert (
      tgt.country_id, 
      tgt.evaluation_date, 
      tgt.population_total_count, 
      tgt.gdp_total_dollars) 
      values (
      cid, 
      eval_date, 
      pop, 
      gdp); 

    exit when c_table.count = 0; --quit condition for cc loop 
    end loop; --end cc loop 
    close cc; 


EXCEPTION 
when ACCESS_INTO_NULL then -- catch error when table does not exist 
    dbms_output.put_line('Error ' || SQLCODE || ': ' || SQLERRM); 

END ; 

我在想,在on聲明,我可以說,沿着線的東西:

on (cid = tgt.country_id AND eval_date = tgt.evaluation_date 
AND pop != tgt.population_total_count AND gdp != tgt.gdp_total_dollars) 

,但肯定有一個更清潔/更有效的方式來做到這一點?

+2

如果你的目標是提高性能,我的第一個偏見就是完全消除循環,只是對所有數據做一個「MERGE」。這可能比在循環中做一個MERGE更快。 SQL應該總是比PL/SQL更快。除此之外,如果你只想更新有變化的行,假設你的列不可爲空,你修改'ON'子句的建議看起來是正確的。如果他們允許NULL值,你的謂詞需要更復雜一點。 –

+0

只有ID和DATE不可空。其餘的都是。 – Ted

+0

然後,你可能需要更多的涉及謂詞(即,如果要從NULL到非NULL值並且如果要從非NULL值變爲NULL,則要更新數據)。我會把它寫成((src.col1!= dest.col1或src.col1爲null,dest.col1不爲null或src.col1不爲null,dest.col1爲null)''但還有其他方法可以構造使用'NVL'來用一個不可能的但非NULL值'nvl(src.col1,'Impossible')!= nvl(dest.col1,'Impossible')替換NULL值的謂詞。 –

回答

1

另一種方法是使用ora_hash來獲得行的散列。所以你的where子句可能是這樣的。

其中ora_hash(src.col1 || || src.col2 || src.col3 src.col4)= ora_hash(src.col1 || || src.col2 || src.col3 src.col4)

相關問題