如何从执行立即语句的输出中获取结果

Posted

技术标签:

【中文标题】如何从执行立即语句的输出中获取结果【英文标题】:How to get result from output of execute immediate statement 【发布时间】:2019-11-15 09:36:58 【问题描述】:

程序仅执行以下输出,但我试图从执行立即语句的输出中获取结果。

当前输出:

PL/SQL procedure successfully completed.

select 'PRJA' AS "PRJ_ID", EVENT, email,modified_by,modified from PRJA.TableX UNION ALL 
select 'PRJB' AS "PRJ_ID", EVENT, email,modified_by,modified from PRJB.TableX UNION ALL 
select 'PRJC' AS "PRJ_ID", EVENT, email,modified_by,modified from PRJC.TableX UNION ALL 
select 'PRJD' AS "PRJ_ID", EVENT, email,modified_by,modified from PRJD.TableX;

我期待选择/输出上面的结果:

SET SERVEROUTPUT ON

Declare
TYPE T IS TABLE OF MYTABLE.ID%TYPE INDEX BY PLS_INTEGER;
MYROW T;
v_sql varchar2(500);
v_sql2 varchar2(500);
v_prj_id varchar2(4000):='PRJA,PRJB,PRJC,PRJD';

BEGIN

 FOR i IN (SELECT trim(regexp_substr(v_prj_id, '[^,]+', 1, LEVEL)) l
         FROM dual 
         CONNECT BY LEVEL <= regexp_count(v_prj_id, ',') + 1 
 ) LOOP


   v_sql :=  v_sql || 'select '''|| i.l ||''' AS "PRJ_ID", EVENT, email,modified_by,modified from ' 
  || i.l || '.TableX UNION ALL ' || chr(10) ;

  END LOOP;

   v_sql2 :=  RTRIM(v_sql, 'UNION ALL ' || chr(10) ) || ';';

   EXECUTE IMMEDIATE v_sql2 BULK COLLECT INTO MYROW;
   DBMS_OUTPUT.PUT_LINE(MYROW.XXX);
   END;
      /

【问题讨论】:

你尝试设置 serveroutput on @Andrew 是的。它也列在我的查询顶部。 尝试使用 v_sql2 := RTRIM(v_sql, 'UNION ALL ' || chr(10) ) || ';';立即执行 v_sql2 批量收集到 MYROW; DBMS_OUTPUT.PUT_LINE(MYROW.XXX);在 for 循环中,因为您要打印此选择查询的结果,而不是选择查询本身... 【参考方案1】:

您的代码有两个明显的问题:

    目标集合的投影与动态查询的投影不匹配。它们的列数(和数据类型)必须相同。 dbms_output 语句将失败,因为 MYROW 是一个集合,而put_line() 只接受标量值。

组装查询的循环也很笨拙。我们可以使用 PL/SQL 集合使其更整洁。

declare
  -- record type to match projection of required output
  type r is record (
   prj_id        varchar2(30)
   , event       PRJA.TableX.event%type
   , email       PRJA.TableX.email%type
   , modified_by PRJA.TableX.modified_by%type
   , modified    PRJA.TableX.modified%type
  );

  TYPE T IS TABLE OF R;
  MYROWS T; -- plural because it's a table not a record variable

  v_sql       varchar2(32767);

  -- collection of schemas to query ...
  v_prj_ids sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll('PRJA','PRJB','PRJC','PRJD');

BEGIN

  FOR i IN 1 .. v_prj_ids.count() LOOP

  if i > 1 then
    v_sql := v_sql || chr(10) || ' UNION ALL ' || chr(10)
  end if

  v_sql :=  v_sql || 'select '''|| v_prj_ids(i) ||''' AS "PRJ_ID", EVENT, email,modified_by,modified from ' 
  || v_prj_ids(i) || '.TableX ' ;

  END LOOP;

  EXECUTE IMMEDIATE v_sql2 BULK COLLECT INTO MYROWS;

  DBMS_OUTPUT.PUT_LINE(' number of records =' || MYROWS.count());

END;
/

注意:未测试,因为我无法访问多用户环境

【讨论】:

【参考方案2】:

您的变量MYROW 的类型为T,即TABLE OF MYTABLE.ID%TYPE,因此每个数据类型记录只能保存一个值,与MYTABLE.ID 的数据类型相同。

在您的代码中,您正在获取 "PRJ_ID", EVENT, email, modified_by, modified (5) 列并尝试将其分配给无法容纳这么多列的 MYROW

如果您只对PRJ_ID 字段感兴趣,则必须从您的选择子句中删除除“PRJ_ID”之外的所有列。

类似:

V_SQL := V_SQL
         || 'select ''' || I.L
         || ''' AS "PRJ_ID" ' -- , EVENT, email,modified_by,modified from
         || I.L || '.TableX UNION ALL '|| CHR(10);

如果您想要所有数据,那么您需要创建可以保存适当属性的对象。请参阅此forum 以实现对象表。

干杯!!

【讨论】:

以上是关于如何从执行立即语句的输出中获取结果的主要内容,如果未能解决你的问题,请参考以下文章

通过运行一次语句同时从 Postgresql 获取结果和解释分析输出

使用调用过程的执行立即语句中的 out 参数

PL/SQL中测试存储过程,如何立即输出DBMS_OUTPUT的语句。

如何从 Java 中的 Oracle SQL 选择中获取原始脚本输出而不是查询结果

PL/SQL - dbms 输出立即执行的结果

plsql 中如何使用dbms_output输出结果