从Oracle中的动态SQL获取结果集中的结果

时间:2010-04-05 17:45:25

标签: oracle resultset dynamic-sql oracle-sqldeveloper

这个问题类似于我在StackOverflow上找到的其他几个问题,但这些差异对于我来说是一个非常重要的保证一个新问题,所以这里是:

我想从Oracle中的动态SQL获取结果集,然后在类似SqlDeveloper的工具中将其显示为结果集,就像我直接执行动态SQL语句一样。这在SQL Server中很简单,所以具体来说,这是SQL Server中一个在SQL Server Management Studio或Query Explorer中返回结果集的示例:

EXEC sp_executesql N'select * from countries'

或更恰当地说:

DECLARE @stmt nvarchar(100)
SET @stmt = N'select * from countries'
EXEC sp_executesql @stmt

问题"How to return a resultset / cursor from a Oracle PL/SQL anonymous block that executes Dynamic SQL?"解决了问题的前半部分 - 将动态SQL执行到游标中。问题"How to make Oracle procedure return result sets"提供了类似的答案。网络搜索揭示了同一主题的许多变化,所有这些只涉及我问题的前半部分。我发现this post解释了如何在SqlDeveloper中执行此操作,但它使用了SqlDeveloper的一些功能。我实际上使用自定义查询工具,所以我需要在SQL代码中自包含该解决方案。此自定义查询工具同样无法显示print(dbms_output.put_line)语句的输出;它只显示结果集。这里还有one more possible avenue使用'execute immediate ... bulk collect',但是这个例子再次使用dbms_output.put_line语句的循环呈现结果。 This link尝试解决这个问题,但问题从未在那里得到解答。

假设这是可能的,我将添加一个条件:我想这样做而不必定义函数或过程(由于有限的DB权限)。也就是说,我想执行一个包含动态SQL的自包含PL / SQL块,并在SqlDeveloper或类似工具中返回结果集。


总结一下:

  • 我想执行一个任意的SQL语句(因此是动态SQL)。
  • 该平台是Oracle。
  • 解决方案必须是没有程序或功能的PL / SQL块。
  • 必须将输出生成为规范结果集;没有印刷声明。
  • 输出必须在SqlDeveloper中作为结果集呈现,而不使用任何SqlDeveloper特殊功能。

有什么建议吗?

4 个答案:

答案 0 :(得分:0)

尝试尝试这些。

DECLARE
  TYPE EmpCurTyp  IS REF CURSOR;
  v_emp_cursor    EmpCurTyp;
  emp_record      employees%ROWTYPE;
  v_stmt_str      VARCHAR2(200);
  v_e_job         employees.job%TYPE;
BEGIN
  -- Dynamic SQL statement with placeholder:
  v_stmt_str := 'SELECT * FROM employees WHERE job_id = :j';

  -- Open cursor & specify bind argument in USING clause:
  OPEN v_emp_cursor FOR v_stmt_str USING 'MANAGER';

  -- Fetch rows from result set one at a time:
  LOOP
    FETCH v_emp_cursor INTO emp_record;
    EXIT WHEN v_emp_cursor%NOTFOUND;
  END LOOP;

  -- Close cursor:
  CLOSE v_emp_cursor;
END;


declare
  v_rc    sys_refcursor;
begin
   v_rc := get_dept_emps(10);  -- This returns an open cursor
   dbms_output.put_line('Rows: '||v_rc%ROWCOUNT);
   close v_rc;
end;

在此处查找更多示例。 http://forums.oracle.com/forums/thread.jspa?threadID=886365&tstart=0

答案 1 :(得分:0)

在TOAD执行下面的脚本时,系统会提示您输入v_result的类型。从类型选择光标的选择列表中,结果随后显示在Toad的数据网格中(excel电子表格,如结果)。也就是说,当使用游标作为结果时,您应该总是编写两个程序(客户端和服务器)。在这种情况下,'TOAD'将成为客户。

DECLARE
   v_result      sys_refcursor;
   v_dynamic_sql   VARCHAR2 (4000);
BEGIN
   v_dynamic_sql := 'SELECT * FROM user_objects where ' || ' 1 = 1';

   OPEN :v_result FOR (v_dynamic_sql);
END;

Oracle的SQL Developer中可能还有类似的机制来提示绑定。

答案 2 :(得分:0)

你似乎要求一大块PL / SQL代码,它将采用任意查询返回未确定结构的结果集和'forward / restructure'结果集,以某种方式可以很容易地呈现一些“自定义GUI工具“。

如果是这样,请查看DBMS_SQL以获取动态SQL。它有一个DESCRIBE_COLUMNS过程,它从动态SELECT语句返回列。您需要的步骤是,

  1. 解析声明
  2. 描述结果集(列名和数据类型)
  3. 获取每一行,并为每列调用数据类型相关函数将该值返回到本地变量
  4. 将这些局部变量放入定义的结构中以返回调用环境(例如,一致的列名[例如col_1,col_2]可能都是VARCHAR2)
  5. 作为替代方法,您可以尝试将查询构建到XMLFOREST语句中,并将结果解析为XML。


    补充: 与SQL Server不同,Oracle PL / SQL调用不会“自然地”返回单个结果集。它可以打开一个或多个ref游标并将它们传递回客户端。然后,客户端负责从这些ref游标中获取记录和列。如果您的客户端没有/不能处理,那么您不能使用PL / SQL调用。 存储的函数可以返回预定义的集合类型,这可以允许您执行类似“select * from table(func_name('select * from countries'))”的操作。但是,该函数不能执行DML(更新/删除/插入/合并),因为它会破坏该查询的任何一致性概念。此外,返回的结构是固定的,以便

    select * from table(func_name('select * from countries'))
    

    必须返回与

    相同的列(列名和数据类型)
    select * from table(func_name('select * from persons'))
    

    使用DBMS_SQL或XMLFOREST,这样的函数可以采用动态查询并将其重组为预定义的列集(col_1,col_2等),以便可以以一致的方式返回它。但我看不出它的意义。

答案 3 :(得分:0)

我能想到的最接近的事情是创建一个需要权限的动态视图。当然,这将涉及使用PL / SQL块 SQL查询,并且不使用过程/函数。但是,任何动态查询都可以转换并从结果网格中查看,因为它将作为选择查询运行。

{{1}}

enter image description here