2010-09-11 129 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语句。您可以将不同数据库对象的名称作为参数传递或在变量中进行操作。

相关问题