2014-02-18 19 views
0

我希望單個表中的不同值對應不同的列值(esercizio)。單個表上的oracle多重序列

我這樣做,但不是動態創建和使用序列。 如何抽象出問題?

 

    CREATE TABLE Z_TEST 
    (
     ID   NUMBER, 
     ESERCIZIO  NUMBER, 
     DESCRIZIONE VARCHAR2 (200 BYTE) 
    ) 
    LOGGING 
    NOCOMPRESS 
    NOCACHE 
    NOPARALLEL 
    MONITORING; 

    ALTER TABLE Z_TEST ADD ( CONSTRAINT Z_TEST_PK PRIMARY KEY (ID, ESERCIZIO)); 

    CREATE SEQUENCE Z_TEST_SEQ_2010 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 
    CREATE SEQUENCE Z_TEST_SEQ_2011 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 
    CREATE SEQUENCE Z_TEST_SEQ_2012 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 
    CREATE SEQUENCE Z_TEST_SEQ_2013 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 
    CREATE SEQUENCE Z_TEST_SEQ_2014 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 
    CREATE SEQUENCE Z_TEST_SEQ_2015 START WITH 1 MAXVALUE 999999999999999999999999999 MINVALUE 1 NOCYCLE CACHE 20 NOORDER; 

    CREATE OR REPLACE TRIGGER Z_TEST_TRG 
     BEFORE INSERT 
     ON Z_TEST  REFERENCING new AS New old AS Old 
     FOR EACH ROW 
    DECLARE 
     err_code NUMBER; 
     err_msg  VARCHAR2 (200); 
    BEGIN 
     if :new.esercizio = 2010 then select Z_TEST_SEQ_2010.nextval into :new.ID from dual; end if; 
     if :new.esercizio = 2011 then select Z_TEST_SEQ_2011.nextval into :new.ID from dual; end if; 
     if :new.esercizio = 2012 then select Z_TEST_SEQ_2012.nextval into :new.ID from dual; end if; 
     if :new.esercizio = 2013 then select Z_TEST_SEQ_2013.nextval into :new.ID from dual; end if; 
     if :new.esercizio = 2014 then select Z_TEST_SEQ_2014.nextval into :new.ID from dual; end if; 
     if :new.esercizio = 2015 then select Z_TEST_SEQ_2015.nextval into :new.ID from dual; end if; 
    EXCEPTION WHEN OTHERS THEN 
     err_msg := SUBSTR (SQLERRM, 1, 200); 
     err_code := SQLCODE; 
     DBMS_OUTPUT.put_line ('errore: ' || err_code || ' ' || err_msg); 
    END; 
    /
+0

你是什麼意思?你想避免在2016年獲得記錄之前手動創建新序列並更改觸發器,請說?爲什麼ID需要根據該值而不同 - 這意味着ID本身並不是唯一的,所以它不能作爲主鍵,所以它是什麼,以及爲什麼不能使用單個序列來填充柱? –

+0

我有許多舊數據庫訪問誰擁有自己的自動編號,表引用其他,但我有1年的數據庫。 – Albo

+0

我認爲你的兩部分主鍵應該是'ESERCIZIO,ID'而不是'ID,ESERCIZIO'。然後,如果您不關心序列中的空位,則可以爲'ID'的所有值使用相同的序列。你有什麼理由不能有差距嗎? – Glenn

回答

1

你抽象的問題忽略了這樣做的必要性;您正在創建額外的數據,這些數據在當前表單中無法維護;所以你不應該試圖去創造它。

您可以創建單個序列來填充您的ID列,然後使用分析函數ROW_NUMBER()從數據庫中提取時生成二級序列。由於順序始終遞增,因此只要您按「舊」ID列排序,您就可以保證「新」ID列將保持順序。

例如:

select row_number() over (partition by esercizio order by id) as id 
    , descrizione 
    from z_test 

如果你絕對必須存儲在這個數據庫中由於某種原因,你可以有填充它定期次級過程。

另外,在生產代碼中使用DBMS_OUTPUT.PUT_LINE來顯示錯誤幾乎總是不好的做法。它要求有人總是在那裏觀看它們,這是永遠不會發生的。如果你處理一個錯誤,你需要用它做一些事情。


我不同意這樣做,因爲沒有必要,但你可以參考序列動態,如果你想:

CREATE OR REPLACE TRIGGER Z_TEST_TRG 
    BEFORE INSERT 
    ON Z_TEST 
    FOR EACH ROW 
BEGIN 
    execute immediate 'select z_test_seq' || :new.esercizio || '.nextval 
         from dual' 
       into :new.id; 
END; 
+0

坦克但未解決如何將現有數據保存到同一個表中並從現在到未來進行管理。 我建議的代碼是在開發環境中。 – Albo

+0

有一種方法可以使用對象的動態名稱來引用序列(在PLSQL中): like: select'Z_TEST_SEQ_'|| :new.esercizio.nextval into:new.ID from dual; 其中:new.esercizio是書寫行中的esercizio列,並且序列名稱是caluclate?如果可能的話,我可以創建觸發器所需的序列。 – Albo

+1

@Albo - 您可以在觸發器中動態地引用現有序列,但不能創建新序列;你不能在觸發器中執行DDL,因爲它執行了隱式提交。 (你可能能夠解決這個限制,但是這樣做確實表明數據模型問題,我認爲)。 –