4

这个问题与我在 StackOverflow 上发现的其他几个问题相似,但差异对我来说足以证明一个新问题,所以这里是:

我想从Oracle中的动态SQL获取结果集,然后在类似SqlDeveloper的工具中显示为结果集,就好像我直接执行了动态SQL语句一样。这在 SQL Server 中很简单,所以具体来说,这是一个来自 SQL Server 的示例,它在 SQL Server Management Studio 或查询资源管理器中返回结果集:

EXEC sp_executesql N'select * from countries'

或者更准确地说:

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

问题“如何从执行动态 SQL 的 Oracle PL/SQL 匿名块返回结果集/游标?” 解决了问题的前半部分——在游标中执行动态 SQL。“如何使 Oracle 过程返回结果集”问题提供了类似的答案。网络搜索揭示了同一主题的许多变体,所有这些都只解决了我问题的前半部分。我找到了这篇文章解释如何在 SqlDeveloper 中执行此操作,但这使用了 SqlDeveloper 的一些功能。我实际上正在使用自定义查询工具,因此我需要在 SQL 代码中独立包含该解决方案。此自定义查询工具同样无法显示打印 (dbms_output.put_line) 语句的输出;它只显示结果集。这是使用“立即执行...批量收集”的另一种可能途径,但此示例再次使用 dbms_output.put_line 语句循环呈现结果。此链接试图解决该主题,但该问题也从未在那里得到完全回答。

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


所以总结一下:

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

有什么建议么?

4

4 回答 4

2

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

DEFINE view_name = 'my_results_view';
SET FEEDBACK OFF
SET ECHO OFF
DECLARE
  l_view_name VARCHAR2(40)     := '&view_name';
  l_query     VARCHAR2(4000)   := 'SELECT 1+level as id,
                                  ''TEXT''||level as text  FROM DUAL ';
  l_where_clause VARCHAR2(4000):= 
                           ' WHERE TRUNC(1.0) =  1 CONNECT BY LEVEL < 10';
BEGIN
     EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW '
                       || l_view_name
                       || ' AS '
                       || l_query
                       || l_where_clause;
END;
/
 select * from &view_name;

在此处输入图像描述

于 2019-07-04T17:09:08.430 回答
1

您似乎在要求一大块 PL/SQL 代码,该代码将采用任意查询返回未确定结构的结果集,并以某种方式“转发/重组”该结果集,以便某些“自定义 GUI 工具”可以轻松呈现”。

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

  1. 解析语句
  2. 描述结果集(列名和数据类型)
  3. 获取每一行,对于每一列,调用依赖于数据类型的函数将该值返回到一个局部变量中
  4. 将这些局部变量放入定义的结构中以返回调用环境(例如一致的列名 [例如 col_1, col_2] 可能都是 VARCHAR2)

作为替代方案,您可以尝试将查询构建到XMLFOREST语句中,然后从 XML 中解析出结果。


补充:与 SQL Server 不同,Oracle PL/SQL 调用不会“自然”返回单个结果集。它可以打开一个或多个引用游标并将它们传回给客户端。然后,从这些引用游标中获取记录和列成为客户端的责任。如果您的客户不能/不能处理这个问题,那么您就不能使用 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 等),以便可以以一致的方式返回。但我看不出这有什么意义。

于 2010-04-07T07:45:32.910 回答
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

于 2010-04-05T18:00:06.070 回答
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 中可能也有类似的机制来提示绑定。

于 2010-04-05T18:44:25.460 回答