允许用户从动态 SQL SELECT

Allow users to SELECT from dynamic SQL

我一直在查看 Oracle 中的 DBMS_SQL 包,并试图查看是否有创建视图或用户可以 select 从中查看结果的方法动态 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;

但这只是执行语句,并没有return任何东西。我想要的是一个视图,这样用户可以只执行 SELECT the_date FROM some_view 并获得结果。我不会事先知道名称或列数,所以这就是我寻求动态 SQL 解决方案的原因。

如果您希望代码 return rows_processed 变量的值,请使用下面的代码 return 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;

" I will not know the names or number of columns in advance, so that's why I'm after a dynamic SQL solution"

这在 SQL 中很难实现:SQL 完全是关于数据结构的,它确实希望列预先存在。所以你不能在 mutable 数据结构上构建 VIEW。

您可以实现 returns 引用游标的功能。这是一个指向可以被客户端解释的数据结构的指针,比如 JDBC ResultSet。

这是一个示例函数,它采用 table 名称和列名称,组合查询和 returns 它的结果集。

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。


我知道这可能不是您正在寻找的解决方案。如果是这种情况,请编辑您的问题以提供有关您要解决的问题的更多详细信息。