2017-02-28 84 views
-1

在我的模式中,我已經將約250個表從SQL Server遷移到Oracle。事情是,沒有序列或觸發器爲這些表中的任何創建。自動生成Oracle中所有表的序列和觸發器

是否有一種簡單的方法來生成所有的表格序列和觸發器,而不是手動爲每個表執行此操作?

的順序,我需要將是一個例子:

CREATE SEQUENCE "SYSTEM"."SEC_USERS_ID_SEQ" 
    MINVALUE 0 MAXVALUE 999999999999999999999999 
    INCREMENT BY 1 
    START WITH 23 
    CACHE 20 
    NOORDER NOCYCLE NOPARTITION; 

和觸發:

create or replace TRIGGER SEC_USERS_TRIG 
before INSERT 
ON "SYSTEM"."SEC_USERS" 
FOR EACH row 
BEGIN 
    IF inserting THEN 
     IF :NEW."ID" IS NULL THEN 
      SELECT SEC_USERS_ID_SEQ.nextval INTO :NEW."ID" FROM dual; 
     END IF; 
    END IF; 
END; 
+0

生成觸發器是什麼意思?他們在做什麼? – Deltharis

+0

觸發器用於運行插入/更新時增加ID的序列 – Azarix

+0

您可以查看帶有自動增量PK的表格,無需觸發器。 – Aleksej

回答

2

我們可以使用Oracle數據字典視圖(MSSQL INFORMATION_SCHEMA的等價物)生成腳本。 Find out more

本示例生成CREATE SEQUENCE語句。我已經按照你的例子接受了默認值,不需要編碼。序列名稱從表名與列名連接而來,後綴爲「_SEQ」。小心Oracle's thirty character limit on object names

此循環動態查詢表以獲取主鍵列的當前最大值,該列用於派生STARTS WITH子句。

declare 
    curr_mx number; 
begin 
    for lrec in (select ucc.table_name 
         , ucc.column_name 
        from user_constraints uc 
         join user_cons_columns ucc 
          on ucc.table_name = uc.table_name 
          and ucc.constraint_name = uc.constraint_name 
         join user_tab_columns utc 
          on utc.table_name = ucc.table_name 
          and utc.column_name = ucc.column_name 
        where uc.constraint_type = 'P' -- primary key 
        and utc.data_type = 'NUMBER' -- only numeric columns 
       ) 
    loop 
     execute immediate 'select max ('|| lrec.column_name ||') from ' ||lrec.table_name 
      into curr_mx; 
     if curr_mx is null then 
      curr_mx := 0; 
     end if; 
     dbms_output.put_line('CREATE SEQUENCE "'|| user || '"."' 
      || lrec.table_name ||'_'|| lrec.column_name || '_SEQ" ' 
      ||' START WITH ' || to_char(curr_mx + 1) ||';' 
     ); 
    end loop; 
end; 
/

該代碼使用DBMS_OUTPUT,因此,您可以在後臺以供以後使用的文件。如果您使用的是像SQL Developer這樣的IDE,則可能需要啓用DBMS_OUTPUT。請按照this StackOverflow answer中的指導進行操作。

如果您可以保證所有的表都有一個主鍵,它是一個名爲ID的數字列,那麼您可以簡化select語句。相反,如果你的一些主鍵是複合約束,你將需要處理它。

很明顯,我爲了生成序列而努力,因爲它們更簡單。編寫更復雜的觸發器實現留給讀者練習:)

+0

我很抱歉,但我對Oracle並不很有經驗。我運行了腳本,但我不完全知道它在做什麼 – Azarix

+0

@Azarix它應該爲每個具有數字主鍵的表打印一個序列創建語句。你可以運行這些並創建序列。可以通過類比過程來生成觸發器創建腳本。 – Deltharis

+0

@Deltharis這些序列存儲在哪裏?我運行了你寫的代碼,但是當我檢查序列文件夾時,它仍然是空的 – Azarix

0

感謝您的腳本。我稍微修改了一下,並執行了觸發器。隨意使用它。

declare 
    curr_mx number; 
    counter number; 
    seq_name varchar2 (30); 
    trigger_name varchar2 (30); 
begin 
    for lrec in (select ucc.table_name 
         , ucc.column_name 
        from user_constraints uc 
         join user_cons_columns ucc 
          on ucc.table_name = uc.table_name 
          and ucc.constraint_name = uc.constraint_name 
         join user_tab_columns utc 
          on utc.table_name = ucc.table_name 
          and utc.column_name = ucc.column_name 
        where uc.constraint_type = 'P' -- primary key 
        and utc.data_type = 'NUMBER' -- only numeric columns 
       ) 
    loop 
     execute immediate 'select (max ('|| lrec.column_name ||')+1) from ' ||lrec.table_name 
      into curr_mx; 

     IF curr_mx is null THEN 
      curr_mx := 0; 
     END IF; 

     IF counter is null THEN 
      counter := 0; 
     END IF;  

     /* check length of sequence name, 30 is max */ 
     IF length(lrec.table_name ||'_'|| lrec.column_name || '_SEQ') > 30 THEN 

      IF length(lrec.column_name || '_SEQ') > 30 THEN 

       seq_name := counter || '_PKA_SEQ'; 

      ELSE 

       seq_name := lrec.column_name || '_SEQ'; 

      END IF; 

     ELSE 

      seq_name := lrec.table_name ||'_'|| lrec.column_name || '_SEQ'; 

     END IF; 

     /* check length of trigger name, 30 is max */ 
     IF length(lrec.table_name || '_PKA_T') > 30 THEN 

      trigger_name := counter || '_PKA_T'; 

     ELSE 

      trigger_name := lrec.table_name || '_PKA_T'; 

     END IF;   

     counter := counter +1; 

     dbms_output.put_line(
      'CREATE SEQUENCE "' || seq_name || '"' 
      ||' START WITH ' || to_char(curr_mx + 1) ||';' 
     ); 
     dbms_output.put_line('/'); 
     dbms_output.put_line(
      'CREATE OR REPLACE TRIGGER "' || trigger_name || '"' 
      || ' BEFORE INSERT ON "' || lrec.table_name || '"' 
      || ' FOR EACH ROW ' 
      || ' BEGIN ' 
      || ' :new."' || lrec.column_name || '" := "' || seq_name || '".nextval;' 
      || ' END;' 
     ); 
     dbms_output.put_line('/'); 

    end loop; 
end; 

我還檢查了序列和觸發器的名字是否超過30個字符,因爲oracle不會接受這些。

編輯: 不得不在每行之後放置'/',以便您可以在一次運行中執行所有語句。