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

发布于 2024-09-19 13:28:16 字数 557 浏览 8 评论 0原文

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

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 不允许我这样做。有办法解决这个问题吗?非常感谢。

I want to create a stored procedure like this:

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;

Of course, Oracle does not let me do that. Is there a way to work around this problem? Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雨夜星沙 2024-09-26 13:28:16

您有几个不同的表,它们具有完全相同的列名和数据类型?闻起来像是一个狡猾的设计。

无论如何,我们不能像这样在简单的 SQL 中使用变量作为数据库对象。我们必须使用动态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 等视图中。这使得进行影响分析和查找使用给定表或列的所有程序变得更加困难。

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;

One reason to avoid the use of dynamic SQL is that it is open to abuse. Malicious people can use the parameters to attempt to bypass our security. This is called SQL injection. I think people over estimate the significance of SQL injection. It's not automatically a threat. For instance if the procedure is a private procedure in a package (i.e. not declared in the specification) it is unlikely that anybody will hijack it.

But it is sensible to take precautions. DBMS_ASSERT is a package introduced in Oracle 10g to trap attempted SQL injection attacks. It this case it would be worth using it to validate the passed table name

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

This would prevent anybody passing 'pay_table set salary = salary * 10 where id = 1234 --' as the table name parameter.

Another reason to avoid dynamic SQL is that it is harder to get right and harder to debug. The syntax of the actual statement is only checked at run time. It is good to have a complete suite of unit tests which validate all the passed inputs, to ensure that the procedure doesn't hurl a syntax exception.

Finally, such dynamic SQL doesn't show up in views such as ALL_DEPENDENCIES. This makes it harder to undertake impact analysis and locate all the programs which use a given table or column.

莳間冲淡了誓言ζ 2024-09-26 13:28:16

是的,有原生动态 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 结构。

Yes, there is Native Dynamic 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;

Performance and error checking is not as good (no compile-time syntax and schema validation).
Beware of SQL injection.

So, if you have only a couple of tables to choose from, consider using an if/then/else construct with all options instead.

別甾虛僞 2024-09-26 13:28:16

您可以使用动态 SQL 来使用各种 DDL 语句。您可以将不同数据库对象的名称作为参数传递或在变量中进行操作。

You can use all sort of DDL statements using dynamic SQL. You can pass names of different database objects as parameters or manipulate in variables.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文