2015-04-02 48 views
0

我一直在查看Oracle中的DBMS_SQL包,並試圖查看是否有創建視圖的方法或用戶可以從中選擇以查看動態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解決方案。

+0

我不認爲有什麼辦法可以做到這一點。這不是真正的觀點。你也許可以創建一個返回表的函數?查看[this](http://oracle-base.com/articles/misc/pipelined-table-functions.php)表格函數的例子。 – OldProgrammer 2015-04-02 21:11:05

回答

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> 

我建議你堅持使用本地動態SQL(即execute immediate)儘可能的:你可以看到,它比DBMS_SQL真的很簡單。只有當你有一些非常複雜的需求時才能達到DBMS_SQL。


我很欣賞這可能不是您正在尋找的解決方案。如果是這種情況,請編輯您的問題,以提供有關您嘗試解決的問題的更多詳細信息。

0

如果你希望你的代碼返回值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;