如何存储和填充Oracle中的Execute Immediate返回的数据?

时间:2015-08-09 10:44:38

标签: oracle plsql execute-immediate

在我的项目中,我正在尝试执行以下查询:

DECLARE
  Sid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
  Bid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
  ExecuteDSQL varchar2(1000);
  ExecuteDSQLResult varchar2(10000);
BEGIN

  IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
  IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;

  ExecuteDSQL := '  SELECT * FROM iftlog WHERE serverid='''|| Sid
                 || ''' AND bpid=''' || Bid  || '''  ';

  EXECUTE IMMEDIATE ExecuteDSQL INTO ExecuteDSQLResult;

  DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult);

END;
/

查询导致数据类型不一致的错误,除了这个错误之外,问题是我们可以将结果存储到临时表中,就像在MS-SQL中一样吗?我是oracle数据库的新手。我需要临时表来存储1到20之间的记录,我将使用Row_Number()并在我的项目中相应地修改查询。

3 个答案:

答案 0 :(得分:3)

SQL Server临时表的Oracle等效是PL / SQL集合。我们可以使用%rowtype语法来定义与表格投影匹配的本地类型。我们可以使用该类型将局部变量声明为选择的目标。

唉,没有方便的机制来打印记录:您需要在DBMS_OUTPUT.PUT_LINE()调用中指定每个单独的列。

以下是您在idomatic PL / SQL中重写的代码:

DECLARE 

    Sid nvarchar2(30) := '';/*Here the values will come from some other variable>*/
    Bid nvarchar2(30) := '';/*Here the values will come from some other variable>*/

    ExecuteDSQL varchar2(1000) := 'SELECT * FROM iftlog WHERE serverid= :1 AND bpid= :2';
    type iftlog_nt is table of  iftlog%rowtype;

    ExecuteDSQLResult iftlog_nt;

BEGIN

    IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
    IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;

    EXECUTE IMMEDIATE ExecuteDSQL 
        bulk collect into ExecuteDSQLResult
        using sid and bid;

    -- loop through all records in PL/SQL table
    for idx in 1..ExecuteDSQLResult.count()
    loop
        DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult(idx).some_col||'::'||ExecuteDSQLResult(idx).some_other_col);
    end loop;

END;
/

当然,让它重写这样的代码很明显,根本不需要动态SQL。因此,我们可以使用简单的选择替换EXECUTE IMMEDIATE调用:

SELECT * 
bulk collect into ExecuteDSQLResult 
FROM iftlog 
WHERE serverid= sid 
AND bpid= bid;

答案 1 :(得分:1)

Oracle中,您可以使用

  1. Object type/table type
  2. 动态光标
  3. 使用对象类型/表格类型

    CREATE TYPE obj_typ AS OBJECT ( 
       id          number,
       name        VARCHAR2(20)
    );
    /
    
    CREATE TYPE tab_typ AS table of  obj_typ;
    /
    
    declare
        v_type  tab_typ :tab_typ();
        .....
    begin
        .....
        execute immediate 'select obj_typ(id, name) from tbl' into v_type;
        .....
    end;
    

    现在您可以使用v_type作为temp table 等,

    select id from table(v_type);
    

    类型的一个限制是它必须在使用它们之前在模式中创建。

    使用动态光标

    sql_stmt := 'SELECT * FROM emp WHERE job = :j';
    OPEN emp_cv FOR sql_stmt USING my_job;
    

    限制你必须遍历cursor以打赌数据不像temp table那样灵活

答案 2 :(得分:0)

您也可以使用global temporary table

 create global temporary table tmp  
 (serverid varchar2(10),
  bpid varchar2(10),
  txt varchar2(100)
  )
 ON COMMIT PRESERVE ROWS  
 ;

 DECLARE 

 Sid varchar2(30) := '1'; 
 Bid varchar2(30) := '1'; 
 ExecuteDSQL varchar2(1000);

 BEGIN

 ExecuteDSQL := 'insert into  tmp  
 SELECT serverid,bpid,txt FROM iftlog WHERE serverid=:Sid  AND bpid=:Bid';

 EXECUTE IMMEDIATE ExecuteDSQL  using sid, bid;
 commit;
 END;
 /

插入的数据在整个会话期间可用(在提交保留时),可以使用SQL访问

select * from tmp;

另见GTT on SO