立即执行,不显示动态选择语句的记录

时间:2018-08-08 10:05:34

标签: sql oracle plsql

我创建了一个匿名块,该块正在动态创建Select语句。当我执行块时,它仅显示已完成的匿名块,但不显示SQL输出。

declare
    sql_stmt clob; 
    pivot_clause clob; 
begin 
    select listagg('''' || TO_CHAR(PERIOD_NAME,'MON-YY') || ''' as "' || TO_CHAR(PERIOD_NAME,'MON-YY') || '"', ',') 
    within group (order by PERIOD_NAME) 
    into pivot_clause
    from   ( select TO_DATE(PERIOD_NAME,'MON-YYYY') PERIOD_NAME 
             from table1 
             where request_id=<id> 
             group by TO_DATE(PERIOD_NAME,'MON-YYYY') 
             order by TO_DATE(PERIOD_NAME,'MON-YYYY') ASC );

     sql_stmt := 'select * from (select PERIOD_NAME, depreciation 
                                 from table1) pivot (sum(depreciation) for PERIOD_NAME in (' || pivot_clause || '))';

     execute immediate sql_stmt; 
 end; 

4 个答案:

答案 0 :(得分:4)

由于您事先不知道结构,因此由于动态转到结果集中的未知列数,您可以使用ref光标来检索动态查询的结果。

这使用SQL * Plus / SQL Developer / SQLcl绑定变量;

variable rc refcursor;

declare
  sql_stmt clob; 
  pivot_clause clob; 
begin 
  select listagg('''' || TO_CHAR(PERIOD_NAME,'MON-YY') || ''' as "' || TO_CHAR(PERIOD_NAME,'MON-YY') || '"', ',') 
  within group (order by PERIOD_NAME) 
  into pivot_clause from (select TO_DATE(PERIOD_NAME,'MON-YYYY') PERIOD_NAME 
                          from table1 
                          where request_id=<id> 
                          GROUP BY TO_DATE(PERIOD_NAME,'MON-YYYY') 
                          order by TO_DATE(PERIOD_NAME,'MON-YYYY') ASC); 
  sql_stmt := 'select * from (select PERIOD_NAME, depreciation 
                              from table1) pivot (sum(depreciation) for PERIOD_NAME in (' || pivot_clause || '))';

  open :rc for sql_stmt; 
end;
/

print rc

client variable command

variable rc refcursor;

将客户端绑定变量的变量和数据类型声明为参考游标。然后,它不使用open for来处理您的动态语句:

execute immediate

这将打开带有该查询结果的ref游标。 (请注意, open :rc for sql_stmt; 开头的:表示绑定变量引用不是本地PL / SQL变量。)

然后,您可以在代码块之外print使用以下命令设置结果集:

:rc

不同的客户端/ IDE将需要不同的语法。您也可以通过JDBC执行类似的操作。您还可以使用一个返回print rc 的函数。但这取决于您的最终目标是什么。


顺便说一句,此刻所有透视的总计都将为空;您的最终查询需要以枢轴子句所需的格式获取sys_refcursor,例如

PERIOD_NAME

尽管将原始格式保留在ivot子句中会稍微简单一些:

  sql_stmt := 'select * from (select to_char(to_date(PERIOD_NAME, ''MON-YYYY''), ''MON-YY'') as PERIOD_NAME, depreciation 
                              from table1) pivot (sum(depreciation) for PERIOD_NAME in (' || pivot_clause || '))';

带有虚拟表和数据:

declare
  sql_stmt clob; 
  pivot_clause clob; 
begin 

  select listagg('''' || PERIOD_NAME || ''' as "' || TO_CHAR(PERIOD_DATE,'MON-YY') || '"', ',') 
  within group (order by PERIOD_DATE) 
  into pivot_clause from (select distinct PERIOD_NAME, TO_DATE(PERIOD_NAME,'MON-YYYY') PERIOD_DATE 
                          from table1 
                          where request_id=<id>); 

  sql_stmt := 'select * from (select PERIOD_NAME, depreciation 
                              from table1) pivot (sum(depreciation) for PERIOD_NAME in (' || pivot_clause || '))';

  open :rc for sql_stmt; 
end;
/

运行任一版本并执行create table table1 (request_id, period_name, depreciation) as select 1, 'JAN-2018', 42 from dual union all select 1, 'FEB-2018', 11 from dual union all select 1, 'MAR-2018', 22 from dual union all select 1, 'MAR-2018', 33 from dual union all select 2, 'MAR-2018', 44 from dual; 均显示:

print rc

答案 1 :(得分:1)

您只能在一些变量中选择一个动态sql。

示例:

declare
    v_sql VARCHAR2(2000);
    v_col1 varchar2(100);
    v_col2 varchar2(100);
    v_col3 varchar2(100);
begin
    v_sql := 'SELECT 1, 2, 3 FROM DUAL';

    EXECUTE IMMEDIATE v_sql INTO  v_col1, v_col2, v_col3;

    dbms_output.put_line('v_col1: ' || v_col1);
    dbms_output.put_line('v_col2: ' || v_col2);
    dbms_output.put_line('v_col3: ' || v_col3); 
end;

如果有多行,则必须使用游标:

DECLARE
    TYPE c IS REF CURSOR;

    v_c    c;
    v_sql        VARCHAR2(2000);
    v_col1       VARCHAR2(100);
    v_col2       VARCHAR2(100);      
BEGIN
    v_sql := 'SELECT 1, 2 FROM DUAL UNION ALL SELECT 3, 4 FROM DUAL';

    OPEN v_c FOR v_sql;

    LOOP
        FETCH v_c INTO v_col1, v_col2;
        EXIT WHEN v_c%NOTFOUND;

        dbms_output.put_line('v_col1: ' || v_col1 || ', v_col2: ' || v_col2);

    END LOOP;

    CLOSE v_c;
END;

答案 2 :(得分:0)

您需要为EXECUTE IMMEDIATE提供一种将值返回给程序的方法,因此您需要一个INTO子句。

在返回一组行时,将需要一个结构来存储它。

为了举例说明,下面创建一个动态查询,该查询从ALL_OBJECTS视图中进行选择,并将结果放入集合中。

DECLARE
   sql_stmt     CLOB;
   TYPE my_rec_rt IS RECORD
   ( owner         VARCHAR2(30),
     object_name   VARCHAR2(30) );
   TYPE my_rec_t IS TABLE OF my_rec_rt;
   obj_record   my_rec_t;
BEGIN
   sql_stmt :=
      q'[select owner, object_name from all_objects where owner = 'ODS']';

   EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO obj_record;
END;

随后如何查看收藏取决于您的要求。

(您可以在https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/executeimmediate_statement.htm#LNPLS01317的Oracle文档中找到该文档)

答案 3 :(得分:0)

根据您的查询,可能是这样:

declare
    sql_stmt clob; 
    pivot_clause clob; 

    v_PERIOD_NAME DATE;
    v_depreciation NUMBER;
begin 
    select listagg('''' || TO_CHAR(PERIOD_NAME,'MON-YY') || ''' as "' || TO_CHAR(PERIOD_NAME,'MON-YY') || '"', ',') 
    within group (order by PERIOD_NAME) 
    into pivot_clause
    from   ( select TO_DATE(PERIOD_NAME,'MON-YYYY') PERIOD_NAME 
             from table1 
             where request_id=<id> 
             group by TO_DATE(PERIOD_NAME,'MON-YYYY') 
             order by TO_DATE(PERIOD_NAME,'MON-YYYY') ASC );

     sql_stmt := 'select * from (select PERIOD_NAME, depreciation 
                                 from table1) pivot (sum(depreciation) for PERIOD_NAME in (' || pivot_clause || '))';

     execute immediate sql_stmt INTO v_PERIOD_NAME, v_depreciation;
     dbms_output.put_line('v_PERIOD_NAME: ' || v_PERIOD_NAME); 
     dbms_output.put_line('v_depreciation: ' || v_depreciation); 
 end; 

请注意,这假设您将从查询中仅(并且始终)获得单行。否则,您将分别获得异常NO_DATA_FOUNDTOO_MANY_ROWS