2016-01-02 60 views
3

我來自Microsoft SQL環境。我有兩個表tak_netak_beb,我的要求是將值從tak_beb插入到tak_ne如果值不存在,如果它存在只是更新。所以我做了一個合併聲明如下圖所示。但現在我面臨的問題是很快就會有50000計數正在增加序列號.Oracle是穩定的數據庫,我不知道他們爲什麼這樣做。所以我創建一個函數,並防止遞增序列number.My的問題是,它是通過創建一個function.Following正確的做法是我做的oracle中的合併語句問題

merge into tak_ne a using tak_beb b ON (a.NAME=b.NAME) 
When matched then 
    Update 
    Set a.AC_NO = b.AC_NO 
     a.LOCATION = b.LOCATION 
     a.MODEL = b.MODEL 
When not matched then 
insert 
(
sl_no, 
AC_NO, 
LOCATION 
MODEL 
) 
Values 
(
s_slno_nextval 
b.AC_NO 
b.LOCATION 
b.MODEL 
) 

,然後我創建了一個功能

CREATE OR REPLACE FUNCTION s_slno_nextval 
     RETURN NUMBER 
    AS 
     v_nextval NUMBER; 
    BEGIN 
     SELECT s_emp.nextval 
     INTO v_nextval 
     FROM dual; 
     RETURN v_nextval; 
    END; 
+0

甲骨文12標識列 –

回答

3

Oracle使用此方法爲由語句插入的每一行生成唯一的ID。你的TAK_BEB表可能有50000行,所以序列增加了50000次。

要將增量隱藏到函數中並沒有幫助。函數被稱爲AND EXECUTED的每一行,它再次遞增50000次序列。它增加了從雙表中選擇50000的開銷。

如果你真的需要使用一個值從順序由語句插入的所有行,使用包變量:

create package single_id_pkg is 
    id Number; 
    function get_id return number; 
end; 
/

create or replace package body single_id_pkg is 
    function get_id return number is 
    begin 
    return id; 
    end; 
end; 
/

現在使用例如語句觸發器之前,表設置變量:

create trigger tak_ne_BSI_trg 
before insert 
on tak_ne 
begin 
    select s_emp.nextval 
    into single_id_pkg.id 
    from dual; 
end; 

插入觸發器有一個缺點 - 即使語句只更新行,也會觸發MERGE子句(請參閱https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:25733900083512)。如果這是一個問題,您必須以其他方式初始化變量。

下一頁修改語句中使用包變量:

merge into tak_ne a 
    using tak_beb b 
    on (a.NAME=b.NAME) 
when matched then 
    update 
    set a.AC_NO = b.AC_NO 
     a.LOCATION = b.LOCATION 
     a.MODEL = b.MODEL 
when not matched then 
    insert (sl_no, 
      AC_NO, 
      LOCATION, 
      MODEL) 
    values (single_id_pkg.get_id 
      b.AC_NO, 
      b.LOCATION, 
      b.MODEL) 
+0

我會做的R&d關於你的建議。意思是,雖然我曾經在我的問題中做了什麼,有助於停止序列每次增加,直到我插入。但我會盡力在你的方式 – peter

+0

這將使用每個新行相同的ID,我不知道這是什麼OP想要。我知道他想避免爲每個UPDATED行生成一個序列,但是每個INSERTED行應該獲得相同的ID還是不同的ID? –

+0

對,在這種情況下,@Mikhailov會提供更好的洞察 - 直接在觸發器中設置序列ID - 在從序列中選擇之前檢查id是否爲空,因爲MERGE語句觸發每行的更新和插入觸發器 –

2

在使用自動增量領域的Oracle標準方法是使用序列。當然,每次你想使用它時,它都會增加序列號。 但你可以忽略呼叫sequence_name.nextval,隱藏它觸發它也被認爲是標準的方法。

CREATE OR REPLACE EDITIONABLE TRIGGER TAK_NE_ID_TR" 
BEFORE INSERT ON tak_ne 
FOR EACH ROW 
BEGIN 
IF :old.sl_no IS NULL THEN 
    :new.sl_no := s_emp.nextval; 
END IF; 
END; 

如果你想爲一批插入添加相同的ID,你可以使用全局臨時表來保存它。例如,像這樣:

create global temporary table tak_ne_id ("id" number) on commit delete rows 

create or replace trigger tak_ne_BSI_trg 
before insert 
on tak_ne 
begin 
insert into tak_ne_id("id") 
values(s_emp.nextval); 
end 

create or replace TRIGGER TAK_NE_ID_TR 
BEFORE INSERT ON tak_ne 
FOR EACH ROW 
BEGIN 
if :old.sl_no is null then 
    SELECT "id" 
    INTO :new.sl_no 
    FROM tak_ne_id; 
end if; 
END; 

然後你可以使用你合併以前一樣,並沒有調用nextval

merge into tak_ne a using tak_beb b ON (a.NAME=b.NAME) 
    When matched then 
     update 
     set a.AC_NO = b.AC_NO, 
      a.LOCATION = b.LOCATION, 
      a.MODEL = b.MODEL 
    When not matched then 
    insert 
    (
    AC_NO, 
    LOCATION, 
    MODEL 
    ) 
    Values 
    (
    b.AC_NO, 
    b.LOCATION, 
    b.MODEL 
    );