2016-01-22 162 views
2

我的任務是改進舊的PL/SQL和Oracle SQL遺留代碼。總共有大約7000行代碼!現有代碼的一個方面讓我非常驚訝,以前的編碼器通過不編寫任何過程或函數而不必要地創建了數百行代碼 - 相反,編碼器實質上始終重複相同的代碼。PL/SQL存儲過程創建表

例如,在現有的代碼字面上有以下SQL的40或更多次的重複:

CREATE TABLE tmp_clients 
AS 
    SELECT * FROM live.clients; 

CREATE TABLE tmp_customers 
AS 
    SELECT * FROM live.customers; 

CREATE TABLE tmp_suppliers 
AS 
    SELECT * FROM live.suppliers WHERE type_id = 1; 

and many, many more..... 

我很新在PL/SQL寫,但我最近購買的優秀圖書Steven Feuerstein的「Oracle PL/SQL編程」。然而,據我所知,我應該能夠編寫一個可調用的程序,例如:

procedure create_temp_table (new_table_nme in varchar(60) 
    source_table in varchar(60)) 
IS 
    s_query varchar2(100); 
BEGIN 
    s_query := 'CREATE TABLE ' + new_table_nme + 'AS SELECT * FROM ' + source_table; 
    execute immediate s_query; 

EXCEPTION 
    WHEN OTHERS THEN 
     IF SQLCODE = -955 THEN 
      NULL; 
     ELSE 
      RAISE; 
     END IF; 
END; 

然後,我會簡單地調用過程如下:

create_temp_table('tmp.clients', 'live.clients'); 
create_temp_table('tmp.customers', 'live.customers'); 
  1. 是我的建議鑑於上述問題,合理的方法?
  2. 過程調用中的數據類型是否合理,即應該使用varchar2(60),還是可以強制'source_table'參數成爲模式中的表名稱?如果表名超過60個字符會發生什麼?
  3. 我希望能夠通過第三個非必需參數的情況下,數據必須在一個微不足道的限制,即處理案件「WHERE type_id = 1」。如何修改過程以包含僅偶爾使用的參數以及如何修改其餘代碼。我可能會添加某種IF/ELSE語句來檢查第三個參數是否不爲NULL,然後相應地構造s_query。
  4. 如何檢查表格是否已成功創建?
  5. 我想陷阱其他兩個例外,即

    • 新表(如「tmp.clients」)已經存在;和
    • 源表不存在。

    作爲書面處理的EXCEPTION是否處理這些情況?

  6. 更一般地說,從哪裏可以獲得SQL錯誤代碼及其含義?

任何建議對代碼的改進都會非常感激地收到。

+2

只是使用全局臨時表。創建表的代碼讓我認爲原始人熟悉SQL Server。 – kevinsky

回答

2

通過使用GLOBAL臨時表,您可以擺脫很多代碼(逐漸!)。 立即執行並不是一個壞習慣,但如果有其他選項,那麼應該使用它們。全局臨時表在您想要提取和轉換數據的地方很常見,但一旦經過處理,您不再需要它,直到下一次加載。每個用戶只能看到他們插入的數據,並且不會生成重做日誌。如果需要,您可以index the data更快地查詢。

像這樣的事情

- 創建表

create global temporary table GT_CLIENTS 
(
    id     NUMBER(10) not null, 
    Client_id    NUMBER(10) not null, 
    modified_by_id  NUMBER(10), 
    transaction_id  NUMBER(10), 
    local_transaction_id VARCHAR2(30) not null, 
    last_modified_date_tz TIMESTAMP(6) WITH TIME ZONE not null 
) 
on commit preserve rows; 

我建議在提交保存行選項,以便您可以調試你的程序,看什麼地方到表中。

用法是

INSERT INTO GT_CLIENTS 
SELECT * FROM live.clients; 
+0

我不確定我關注。我明白全局臨時表可以用來存儲複雜查詢的結果。然而,如果我所做的只是將現有生產環境中的現有表格複製到我自己的模式中,我看不出所提議的好處。 – user2948208

+0

除非我缺少重點,否則您的解決方案需要爲每個全局臨時表編寫大量代碼,即需要爲GT_CLIENTS,GT_CUSTOMERS,GT_SUPPLIERS等編寫單獨的代碼。這是我嘗試的避免。 – user2948208

+0

我接受全球臨時表還有其他好處(可能會降低內存或存儲空間),我很樂意被別人說服,但目前我無法看到您提出的解決方案如何對我有利,純粹是因爲到需要編寫的代碼量。 – user2948208

0

如果這是你想採取儘量減少路由改變時,那麼誤差源表中不存在爲-942,你會想停下來,而不是繼續作爲你的臨時表不會被創建。同樣,如果你得到的對象已經存在,只要繼續,錯誤將會有問題,因爲你不會用新數據重新加載它 - 創建失敗,所以表仍然有來自上次運行的數據。所以我肯定會更多地考慮一下你的異常處理程序。

這就是說,我也認爲這通常不是最好的辦法。在多用戶環境中創建和刪除對象是一個災難,當有更多合適的選項可用時,這似乎是一種愚蠢的資源浪費。

+0

感謝您建議代碼-942。正如我上面評論的那樣,我很樂意以「最好的方式」做事,但是你沒有真正解釋過,除了說你同意前面的人。爲了達到這個目的,我可能會忽略全局臨時表的要點,因爲它似乎需要爲每個這樣的表編寫大量的代碼。此外,這並不是一個真正的多用戶環境,儘管確實只需要很短的時間就可以將這些表作爲較大查詢的輸入 – user2948208

+1

是的,您需要創建全局臨時表,但是一旦創建完成像當前創建語句一樣插入它們。因此,一旦它們處於模式中,就沒有重要的額外編碼,並且可以消除創建/刪除對象的開銷,並且GTT不會生成重做日誌或回滾信息,從而顯着減少向其中插入數據的開銷。 –