允许用户从动态 SQL 中选择
Posted
技术标签:
【中文标题】允许用户从动态 SQL 中选择【英文标题】:Allow users to SELECT from dynamic SQL 【发布时间】:2015-04-02 19:01:02 【问题描述】:我一直在查看 Oracle 中的 DBMS_SQL 包,并试图查看是否有一种方法可以创建视图或用户可以从中选择以查看动态 SQL 查询的结果。
我有一个基于文档的测试程序:
CREATE OR REPLACE PROCEDURE test_dyn_sql AS
cursor_name INTEGER;
rows_processed INTEGER;
l_query LONG;
BEGIN
l_query := 'SELECT SYSDATE AS the_date, ''ABC'' AS the_string, 1 AS the_int FROM dual';
cursor_name := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cursor_name, l_query, DBMS_SQL.NATIVE);
rows_processed := DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(cursor_name);
DBMS_OUTPUT.put_line('ERROR');
END;
但这只是执行语句并且不返回任何内容。我想要的是一个视图,这样用户就可以执行SELECT the_date FROM some_view
并获得结果。我不会提前知道列的名称或数量,所以这就是我追求动态 SQL 解决方案的原因。
【问题讨论】:
我认为没有任何方法可以做到这一点。这不是视图的真正用途。您也许可以创建一个以某种方式返回表的函数?请参阅this 表函数示例。 【参考方案1】:" 我不会提前知道名称或列数,所以这是 为什么我要使用动态 SQL 解决方案”
这在 SQL 中很难实现:SQL 都是关于数据结构的,它确实希望列存在于前面。因此,您不能在可变数据结构上构建 VIEW。
您可以实现一个返回引用光标的函数。这是一个指向可以由客户端解释的数据结构的指针,例如 JDBC ResultSet。
这是一个示例函数,它采用表名和列名,组合查询并返回其结果集。
CREATE OR REPLACE FUNCTION test_dyn_sql
(tab_name in varchar2
, col_name in varchar2)
return sys_refcursor
AS
return_value sys_refcursor;
BEGIN
open return_value for
'SELECT SYSDATE AS the_date, '||col_name||' FROM '||tab_name;
return return_value;
END;
/
SQL*Plus 中的输出不是很优雅,但你明白了。
SQL> select test_dyn_sql ('EMP', 'NAME') from dual;
TEST_DYN_SQL('EMP','
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
THE_DATE NAME
--------- ------------------------------
03-APR-15 FOX IN SOCKS
03-APR-15 MR KNOX
03-APR-15 DAISY-HEAD MAYZIE
SQL>
我建议您尽可能坚持使用 Native Dynamic SQL(即execute immediate
):正如您所看到的,与 DBMS_SQL 相比,它确实非常简单。仅当您有一些极其复杂的需求时才使用 DBMS_SQL。
我很感激这可能不是您正在寻找的解决方案。如果是这种情况,请编辑您的问题,以提供有关您要解决的问题的更多详细信息。
【讨论】:
【参考方案2】:如果您希望您的代码返回 rows_processed 变量的值,请使用下面将返回 0 的代码。
CREATE OR REPLACE FUNCTION test_dyn_sql(asd INTEGER) RETURN INTEGER AS
cursor_name INTEGER;
rows_processed INTEGER;
l_query LONG;
BEGIN
l_query := 'SELECT SYSDATE AS the_date, ''ABC'' AS the_string, 1 AS the_int FROM dual';
cursor_name := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cursor_name, l_query, DBMS_SQL.NATIVE);
rows_processed := DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);
RETURN rows_processed;
EXCEPTION
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(cursor_name);
DBMS_OUTPUT.put_line('ERROR');
RETURN 0;
END;
这是从 plsql 调用函数的方式
DECLARE
rows_precessed INTEGER;
BEGIN
rows_precessed := test_dyn_sqll(0);
DBMS_OUTPUT.put_line(rows_precessed);
END;
【讨论】:
以上是关于允许用户从动态 SQL 中选择的主要内容,如果未能解决你的问题,请参考以下文章