我需要在Oracle上使用动态SQL执行,我不知道运行前SQL中使用的绑定变量的确切数量。
有没有办法在某种程度上调用EXECUTE IMMEDIATE
时使用可变数量的绑定变量?
更具体地说,我需要将一个参数传递给未知的SQL,但我不知道它在那里的使用频率。
我试过像
这样的东西EXECUTE IMMEDIATE 'SELECT SYSDATE FROM DUAL WHERE :var = :var' USING 1;
但它以ORA-01008: not all variables bound.
答案 0 :(得分:9)
您无法使用EXECUTE IMMEDIATE
执行此操作。但是,您可以使用Oracle的DBMS_SQL
包来完成此操作。 Database Application Developer's Guide对您熟悉的EXECUTE IMMEDIATE
和dbms_sql
方法进行了比较。 This page文档DBMS_SQL
,但有一些示例(上面已链接)应该让您入门(示例1是运行可能具有任意数量的绑定变量的语句的简单情况)。从编码的角度来看,DBMS_SQL
更加繁琐,但它可以让你做任何你能想到的事情。
允许在SQL中出现多个绑定变量实例。但是,您必须知道用作绑定变量的名称(例如:在您的情况下为var),以便将其传递给DBMS_SQL.BIND_VARIABLE
。
答案 1 :(得分:7)
您还可以使用WITH
语句解决此问题。通常使用DBMS_SQL
会更好,但有时这是一种更简单的方法:
BEGIN
EXECUTE IMMEDIATE 'WITH var AS (SELECT :var FROM dual) SELECT SYSDATE FROM DUAL WHERE (SELECT * FROM var) = (SELECT * FROM var)' USING 1;
END;
答案 2 :(得分:2)
此Thread on AskTom详细介绍了主题。
在您的情况下,如果您想传递一个参数或者没有传递,您可以构建两个具有单个参数的查询,并且在其中一个查询中不使用它(即谓词始终为true),如下所示:
-- query1
SELECT * FROM DUAL WHERE dummy = :x;
-- query2
SELECT * FROM DUAL WHERE nvl(:x, 1) IS NOT NULL;
您可以优化谓词,以便优化器能够理解它始终是真的。
答案 3 :(得分:1)
可以像Steve Broberg解释的那样使用dbms_sql
,但是很多客户端无法使用(读取)生成的游标。 Oracle 11添加了一个转换函数(dbms_sql.to_refcursor
),可以将dbms_sql
游标转换为引用游标,但由于某种原因,不能在.Net应用程序中使用这个转换后的引用游标。可以在.net中使用正常的引用游标,但不能使用曾经是dbms_sql
游标的引用游标。
那么什么样的客户端会消耗这个游标?
答案 4 :(得分:1)
更具体地说,我需要将一个参数传递给未知的SQL,但我不知道它将在那里使用的频率。
我实际上几天前碰到了同样的问题,而且有一位朋友与我分享了一种与EXECUTE IMMEDIATE
完全相同的方法。
它涉及生成PLSQL块而不是SQL块本身。将EXECUTE IMMEDIATE
与PLSQL代码块一起使用时,可以按名称绑定变量,而不是仅按位置绑定。
查看我的示例/代码以及我自己的类似问题/答案帖子: