是否可以将表名作为参数传递给Oracle?

Vim*_*987 1 sql oracle plsql stored-procedures

我想创建一个这样的存储过程:

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;
Run Code Online (Sandbox Code Playgroud)

当然,Oracle不允许我这样做.有办法解决这个问题吗?非常感谢你.

APC*_*APC 12

You have several different tables with exactly the same column names and data types? Smells like a dodgy design.

Anyway, we cannot use variables as database objects in straightforward SQL like that. We have to use dynamic 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;
Run Code Online (Sandbox Code Playgroud)

避免使用动态SQL的一个原因是滥用它是开放的.恶意用户可以使用这些参数来尝试绕过我们的安全性.这称为SQL注入.我认为人们过度估计了SQL注入的重要性.它不会自动成为威胁.例如,如果过程是包中的私有过程(即未在规范中声明),则任何人都不可能劫持它.

但采取预防措施是明智的.DBMS_ASSERT是Oracle 10g中引入的一个包,用于捕获尝试的SQL注入攻击.在这种情况下,值得使用它来验证传递的表名

....
'UPDATE '|| DBMS_ASSERT.simple_sql_name(pADSLTable)
....  
Run Code Online (Sandbox Code Playgroud)

这将阻止任何人'pay_table set salary = salary * 10 where id = 1234 --'作为表名参数传递.

避免动态SQL的另一个原因是,更难以正确和更难调试.仅在运行时检查实际语句的语法.最好有一套完整的单元测试来验证所有传递的输入,以确保程序不会抛出语法异常.

最后,这样的动态SQL不会出现在诸如ALL_DEPENDENCIES之类的视图中.这使得进行影响分析和查找使用给定表或列的所有程序变得更加困难.