plsql:执行查询:无效的标识符

时间:2016-01-07 07:02:22

标签: dynamic plsql execute rowtype

为什么我不能执行stmt查询?

它显示tabb是无效的标识符。

  TYPE tab_row IS TABLE OF tab_name%ROWTYPE;
  tabb tab_row;
  TYPE cur_ref Is Ref Cursor;
  c           cur_ref;
  stmt_string Varchar2(1000);
  stmt Varchar2(1000);
Begin
   stmt_string := 'Select * from ' || tab1 || ' mft 
             Where mft.mfmt_id IS NOT NULL 
             and mft.MFMT_FLAG IS NULL';
  Open c For stmt_string;
  Fetch c bulk collect into tabb;
  Close c;
 stmt:= 'Update '|| tab || ' m 
    Set m.mfmt_mat_bnr = tabb(i).mfmt_mat_bnr, 
    m.mfmt_mat_type = tabb(i).mfmt_mat_type,
    m.mfmt_be_seg = tabb(i).mfmt_be_seg
    Where m.mfmt_id = tabb(i).mfmt_id';

  For i in 1..tabb.count loop    
    Execute Immediate stmt;
  End loop;
 End;

2 个答案:

答案 0 :(得分:0)

我还没有看到tabb被宣布在哪里。正如您在评论中提到的,它是一个集合。

从您的代码中我可以理解您正在循环遍历此集合的值。这意味着这些值是变量,即每次迭代都会改变值。因此,您需要使用它们。

你当前的动态语句,这个值是静态字符串。每次迭代时,此Set m.mfmt_mat_bnr = tabb(i).mfmt_mat_bnr,将生成相同的字符串。因此,您需要将其更改为Set m.mfmt_mat_bnr = '|| tabb(i).mfmt_mat_bnr||', ...etc

我可以按如下方式重写您的代码:

TYPE tab_row IS TABLE OF tab_name%ROWTYPE;
tabb tab_row;
TYPE cur_ref Is Ref Cursor;
c           cur_ref;
stmt_string Varchar2(1000);
stmt Varchar2(1000);
Begin
stmt_string := 'Select * from ' || tab1 || ' mft 
            Where mft.mfmt_id IS NOT NULL 
            and mft.MFMT_FLAG IS NULL';
Open c For stmt_string;
Fetch c bulk collect into tabb;
Close c;
stmt:= 'Update '|| tab || ' m 
Set m.mfmt_mat_bnr = '||tabb(i).mfmt_mat_bnr||', 
m.mfmt_mat_type = '||tabb(i).mfmt_mat_type||',
m.mfmt_be_seg = '||tabb(i).mfmt_be_seg||'
Where m.mfmt_id = '||tabb(i).mfmt_id;

 For i in 1..tabb.count loop    
    Execute Immediate stmt;
  End loop;
 End;

由于此代码未经过测试,我强烈建议您先确认一件事。是tabb是否在范围内正确声明。

答案 1 :(得分:0)

如果问题出在您执行语句的循环中,可以尝试使用EXECUTE IMMEDIATE .. USING语句吗?

语法为:

EXECUTE IMMEDIATE <SQL Command>
        [INTO <variable list>]
        [USING <bind variable list>];

您可以尝试下面的代码,然后:

    DECLARE
        -- your tab1 may contain some insignificant columns with values (especially huge ones e.g. CLOB/BLOB)
        -- which will extremely affect procedure's efficiency, so it's a better practice to select only those values that we need
        TYPE t_tab_rec  IS RECORD (
            mfmt_mat_bnr                tab_name.mfmt_mat_bnr%TYPE
            ,mfmt_mat_type              tab_name.mfmt_mat_type%TYPE
            ,mfmt_be_seg                tab_name.mfmt_be_seg%TYPE
            ,mfmt_id                    tab_name.mfmt_id%TYPE
        );

        TYPE t_tab_arr IS TABLE OF t_tab_rec;
        tabb            t_tab_arr := NEW t_tab_arr();
        TYPE ref_cur IS REF CURSOR RETURN t_tab_rec;    -- to assure cursor is returning t_tab_rec type records
        c               cur_ref;
        stmt_select     VARCHAR2(1000);
        stmt_upadte     VARCHAR2(1000);
    BEGIN

        stmt_select := 
            'SELECT
                mft.mfmt_mat_bnr
                ,mft.mfmt_mat_type
                ,mft.mfmt_be_seg
                ,mft.mfmt_id
            FROM
                '||tab1||' mft
            WHERE
                mft.mfmt_id IS NOT NULL
                AND mft.mfmt_flag IS NOT NULL';

        OPEN c FOR stmt_select;
        FETCH c BULK COLLECT INTO tabb;
        CLOSE c;

        stmt_upadte := 
            'UPDATE '||tab||'
            SET mfmt_mat_bnr = :p_mfmt_mat_bnr
                ,mfmt_mat_type = :p_mfmt_mat_type
                ,mfmt_be_seg = :p_mfmt_be_seg
            WHERE
                mfmt_id = :p_mfmt_id';

        FOR idx IN tabb.FIRST .. tabb.LAST
        LOOP
            EXECUTE IMMEDIATE stmt_update USING tabb(idx).mfmt_mat_bnr, tabb(idx).mfmt_mat_type, tabb(idx).mfmt_be_seg, tabb(idx).mfmt_id;
        END LOOP;

    END;
    /