2010-09-11 30 views
1

我想創建這樣一個存儲過程:是否可以在Oracle中將表名稱作爲參數傳遞?

PROCEDURE P_CUSTOMER_UPDATE 
    (
     pADSLTable IN Table, 
     pAccountname IN NVARCHAR2, 
     pStatus IN NUMBER, 
     pNote IN NVARCHAR2, 
     pEmail IN NVARCHAR2, 
     pMobi IN NVARCHAR2, 
     pServiceTypeID IN NUMBER, 
     pDate IN DATE 
) 
    IS 
    BEGIN 
     UPDATE pADSLTable 
     SET STATUS = pStatus, NOTE = pNote, EMAIL = pEmail, MOBI = pMobi, SERVICETYPE_ID = pServiceTypeID, ACTIVATION_DATE = pDate 
     WHERE ACCOUNT_NAME = pAccountname; 
    END; 

當然,Oracle不會讓我這樣做。有沒有辦法解決這個問題?非常感謝你。

回答

11

你有幾個不同的表具有完全相同的列名和數據類型?聞起來像一個狡猾的設計。

無論如何,我們不能像這樣直接使用變量作爲數據庫對象。我們必須使用動態SQL。

PROCEDURE P_CUSTOMER_UPDATE 
    (
     pADSLTable IN USER_TABLES.table_name%type, 
     pAccountname IN NVARCHAR2, 
     pStatus IN NUMBER, 
     pNote IN NVARCHAR2, 
     pEmail IN NVARCHAR2, 
     pMobi IN NVARCHAR2, 
     pServiceTypeID IN NUMBER, 
     pDate IN DATE 
) 
    IS 
    BEGIN 
     execute immediate 
      'UPDATE '||pADSLTable 
      ||' SET STATUS = :1, NOTE = :2, EMAIL = :3, MOBI = :4, SERVICETYPE_ID = :5, ACTIVATION_DATE = :6' 
      ||' WHERE ACCOUNT_NAME = :7' 
     using pStatus, pNote, pEmail, pMobi, pServiceTypeID, pDate, pAccountname; 
    END; 

避免使用動態SQL的一個原因是它可以被濫用。惡意的人可以使用這些參數來繞過我們的安全。這被稱爲SQL注入。我認爲人們高估了SQL注入的重要性。這不會自動成爲威脅。例如,如果程序是包中的私有程序(即未在規範中聲明),則任何人都不可能劫持它。

但是採取預防措施是明智的。 DBMS_ASSERT是Oracle 10g中引入的一個包,用於捕獲嘗試的SQL注入攻擊。這這種情況下,它會使用它來驗證所傳遞的表名

.... 
'UPDATE '|| DBMS_ASSERT.simple_sql_name(pADSLTable) 
.... 

這將防止任何人通過'pay_table set salary = salary * 10 where id = 1234 --'作爲表名的參數值。

避免動態SQL的另一個原因是難以正確和更難調試。實際語句的語法只在運行時檢查。最好有一套完整的單元測試來驗證所有通過的輸入,以確保該過程不會拋出語法異常。

最後,這種動態SQL不會顯示在諸如ALL_DEPENDENCIES的視圖中。這使得難以進行影響分析並找到使用給定表或列的所有程序。

+0

DBMS_ASSERT沒有記錄在10gR2中,儘管它存在。感謝您指出。 – 2010-09-13 14:45:50

1

是的,有本地動態SQL:

EXECUTE IMMEDIATE 'UPDATE ' || pADSLTable || 
    'SET STATUS = :1, NOTE = :2, EMAIL = :3, MOBI = :4, SERVICETYPE_ID = :5, ACTIVATION_DATE = :6 WHERE ACCOUNT_NAME = :7 ' 
    USING pStatus, pNote, pEmail, pMobi, pServiceTypeId, pDate, pAccountname; 

性能和錯誤檢查也沒有那麼好(無編譯時語法和模式驗證)。 注意SQL注入。因此,如果您只有幾個表可供選擇,請考慮使用帶有所有選項的if/then/else結構。

0

您可以使用各種使用動態SQL的DDL語句。您可以將不同數據庫對象的名稱作爲參數傳遞或在變量中進行操作。

相關問題