从Oracle中的Dynamic SQL中获得结果
-
24-09-2019 - |
题
这个问题类似于我在Stackoverflow上发现的其他几个问题,但是差异对我来说足够显着,可以保证一个新的问题,因此,这里是:
我想从Oracle中的Dynamic SQL中获得结果集,然后将其作为结果设置在类似于SQLdeveloper的工具中,就像我直接执行了Dynamic 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
问题 “如何从执行动态SQL的Oracle PL / SQL匿名块中返回结果集 /光标?” 解决问题的前半部分 - 将动态SQL运用到光标中。问题 “如何使Oracle过程返回结果集” 提供类似的答案。 Web搜索揭示了相同主题的许多变体,所有这些都仅解决了我问题的上半年。我发现 这个帖子 解释如何在SQLDEVEVER中进行操作,但使用SQLDEVEVEL的一些功能。我实际上正在使用自定义查询工具,因此我需要在SQL代码中独立的解决方案。同样,此自定义查询工具也没有能力显示打印输出(dbms_output.put_line)语句;它仅显示结果集。这里是 另一个可能的途径 使用“立即执行...批量收集”,但是此示例再次使用dbms_output.put_line语句的循环呈现结果。 这个链接 试图解决该主题,但这个问题也从未完全得到回答。
假设这是可能的,我将增加一个条件:我想这样做,而无需定义功能或过程(由于DB权限有限)。也就是说,我想执行一个包含动态SQL的独立PL/SQL块,并返回SQLdeveloper或类似工具中的结果集。
因此总结:
- 我想执行任意SQL语句(因此动态SQL)。
- 该平台是Oracle。
- 该解决方案必须是没有过程或功能的PL/SQL块。
- 输出必须作为规范结果集生成;没有打印语句。
- 在不使用任何SQLDEVEVER特殊功能的情况下,输出必须在SQLDEVEVER中渲染。
有什么建议么?
解决方案
您似乎正在要求一块PL/SQL代码,该代码将采用不确定的结构的任意查询返回结果集和以某种方式设置的“正向/重组”,以便通过某些“自定义GUI工具”轻松地呈现结果。 ”。
如果是这样,请查看动态SQL的DBMS_SQL。它具有描述_columns步骤,该过程从动态选择语句中返回列。您需要的步骤是
- 解析声明
- 描述结果集(列名和数据类型)
- 获取每一行,对于每一列,请调用datatype依赖函数以将该值返回到本地变量
- 将这些本地变量放入定义的结构中以返回调用环境(例如,一致的列名[例如Col_1,col_2],可能是所有varchar2)
作为替代方案,您可以尝试将查询构建为 xmlforest 声明,并将结果解析为XML。
添加:与SQL Server不同,Oracle PL/SQL调用不会“自然地”返回单个结果集。它可以打开一个或多个裁判光标,并将其传递给客户。然后,从这些裁判光标中获取记录和列成为客户的责任。如果您的客户不使用/无法处理,那么您将无法使用PL/SQL调用。存储的功能可以返回预定义的收集类型,该类型可以使您可以执行“从表(Func_name('select * from consife'select * select * select *))之类的事情”。但是,该函数无法执行DML(update/delete/insert/Merge),因为它会吹走该查询的任何一致性概念。加上返回的结构是固定的,以便
select * from table(func_name('select * from countries'))
必须返回相同的一组列(列名和数据类型)
select * from table(func_name('select * from persons'))
使用DBMS_SQL或XMLFOREST,可以使用动态查询并将其重组为预定义的列集(COL_1,COL_2等),以便可以以一致的方式将其返回。但是我看不到它的意义是什么。
其他提示
尝试这些。
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
在执行下面的脚本时,在蟾蜍中,将提示您的V_Result类型。从类型的选择“选择光标”中,结果将显示在Toad的数据网格中(Excel电子表格类似于结果)。也就是说,在与光标一起工作时,您应该始终编写两个程序(客户端和服务器)。在这种情况下,“蟾蜍”将是客户。
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开发人员也可能有类似的机制来提示绑定。
我能想到的最接近的事情是创建一个动态视图,以便为其提供许可。这肯定会涉及使用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;