Oracle PLSQL无效游标错误我不明白

时间:2018-01-20 23:59:35

标签: oracle plsql cursor

在谈到PL / SQL时,我仍然是一个相对较新的人。

在Linux RHEL 6.8上使用Oracle 12c,以下shell脚本将尝试激活表集合中的所有RI约束,如果它们因父键失败而失败,它将转储前100行(或更少)违规数据。或者至少那是目标。由于脚本主要处理12c上的系统表(只有一个小的用户表列表,这对我的安装来说是唯一的),所以我完全从我的环境中包含了整个事物。

主要工作发生在异常处理中,其中查询系统表以获得约束,并且从这些数据形成用户查询。

作为一个额外的目标,输出相当混乱,我想要清理它,但首先它必须工作:)

我为表格得到的输出/错误如下:

  

错误处理表NRNG_MTC_VST约束名称:   SYS_C0011790最终SQL = SELECT DISTINCT NRNG_MTC_VST.LOG_CRT_DT,   来自ODB_PRIMARY.NRNG_MTC_VST的NRNG_MTC_VST.NRRNG_MTC_LG_ID   EXISTS(从ODB_PRIMARY.NRNG_MTC_LOG中选择1   NRNG_MTC_VST.LOG_CRT_DT = NRNG_MTC_LOG.LOG_CRT_DT AND   NRNG_MTC_VST.NRRNG_MTC_LG_ID = NRNG_MTC_LOG.NRRNG_MTC_LG_ID)FETCH   仅限第一行100行   --- xxx结束SQL DECLARE   *第1行的错误:ORA-01001:无效游标ORA-06512:第111行ORA-02298:无法验证(ODB_PRIMARY.SYS_C0011790) - 父键   找不到

我的print_line的输出SQL是正确的,如果直接粘贴到SQLDeveloper会话中,它将起作用。关于如何定义光标,我真的很蠢。我不明白。

脚本的全文。 BYW,如果您发现应该与错误无关的其他骨头更改,请同时建议。

cd $OGGHOME/scripts
export ORACLE_SID=odbod07 $ORACLE_HOME/bin/sqlplus <<-EOF / as sysdba
alter session set container=p01_odbod07; 
set echo on set feedback on
set heading off 
set serveroutput on size 10000

DECLARE    finalsql varchar2(2048);   
part1sql varchar2(1024) ;  
part2sql varchar2(1024) := ' ';   
cownername varchar2(1024);  
ctablename varchar2(1024);   
pownername varchar2(1024);   
ptablename varchar2(1024);   
cnt number := 0;
-- Weak cursor defs   
my_cursor sys_refcursor;

BEGIN   FOR i in (
                select owner, table_name, constraint_name
                from dba_constraints
                where constraint_type = 'R'
                and status = 'DISABLED'
                and owner = 'ODB_PRIMARY'
                and TABLE_NAME in 
-- enter user tables with RI constraints here
('RRNG_MTC_STN_CPLY',   
'NRNG_MTC_VST_MTRL_USG',    
'NRNG_MTC_VST',     
'CAR_CORE',
'NRNG_MTC_LOG')) 
-- end user table definitions, rest of code should rely only on system tables   
LOOP BEGIN
   dbms_output.put_line('alter table '||i.owner|| '.' || 
        i.table_name || ' enable constraint '||i.constraint_name);
   execute immediate 'alter table '||i.owner|| '.' || 
        i.table_name || ' enable constraint '||i.constraint_name;
EXCEPTION
-- exception handling - dump offending data 
WHEN OTHERS THEN      -- take all exceptions for now        
  dbms_output.put_line ('ERROR Handling here for table ' ||
      i.table_name || ' Constraint Name: ' ||i.constraint_name);
  finalsql := 'SELECT DISTINCT ';           
  part1sql := '';           
  part2sql := ' ';          
  cnt := 0;

  for constraint in (           
    SELECT      ucc1.OWNER as childowner,
                ucc1.TABLE_NAME as childtable,
                ucc1.column_name as childcolumn,
                ucc2.OWNER as parentowner,
                ucc2.TABLE_NAME as parenttable,
                ucc2.column_name as parentcolumn,
                utc1.data_type as childdatatype,
                utc1.data_length as childdatalen            
    FROM        all_constraints uc ,
                all_cons_columns ucc1 ,
                all_cons_columns ucc2,
                all_tab_columns utc1            
    WHERE       
                uc.constraint_name       = ucc1.constraint_name
                AND uc.r_constraint_name = ucc2.constraint_name
                AND ucc1.POSITION        = ucc2.POSITION
                AND ucc1.table_name      = utc1.table_name
                AND ucc1.column_name     = utc1.column_name 
                AND uc.constraint_type   = 'R'
                AND uc.constraint_name   = i.constraint_name        
    ORDER BY ucc1.TABLE_NAME , uc.constraint_name)          
    loop
        cownername := constraint.childowner;
        ctablename := constraint.childtable;
        pownername := constraint.parentowner;
        ptablename := constraint.parenttable;
        if cnt > 0 then
            part1sql := part1sql || ' , ';
            part2sql := part2sql || ' AND ';
        end if;
        part1sql := part1sql || constraint.childtable ||
                    '.'||constraint.childcolumn || ' ';
        part2sql := part2sql || constraint.childtable || '.' 
                 || constraint.childcolumn || ' = ' 
                 || constraint.parenttable || '.' ||
                    constraint.parentcolumn;
        cnt := cnt + 1;             
    end loop;

    finalsql := finalsql || part1sql || 
                ' FROM ' ||  ' ' || cownername  || 
                '.' || ctablename ||  
                ' WHERE NOT EXISTS (SELECT 1 FROM ' || 
                pownername || '.' || ptablename || 
               ' WHERE ' || part2sql || ') FETCH FIRST 100 rows only';

    dbms_output.put_line ('Final SQL = ' || finalsql);
    dbms_output.put_line ('---xxx End SQL');            
    open my_cursor for finalsql;            
    dbms_sql.return_result(my_cursor);              
    close my_cursor;
--  EXECUTE IMMEDIATE finalsql;         
END;    
end loop; end; 
/ 
EOF

非常感谢您提供的任何帮助。 布赖恩

4 个答案:

答案 0 :(得分:1)

只是将其缩小到simple test case,我认为这是您看到的错误:

declare
    my_cursor sys_refcursor;
begin
    open my_cursor for 'select ''Hello, world'' as message from dual';
    dbms_sql.return_result(my_cursor);
    close my_cursor;  -- << Remove this line
end;
/

ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 6

这是因为当您已将光标传递给dbms_sql进行处理时,您试图关闭光标。删除close my_cursor

declare
    my_cursor sys_refcursor;
begin
    open my_cursor for 'select ''Hello, world'' as message from dual';
    dbms_sql.return_result(my_cursor);
end;
/

PL/SQL procedure successfully completed.

ResultSet #1

MESSAGE
------------
Hello, world

1 row selected.

答案 1 :(得分:0)

mydata

答案 2 :(得分:0)

以下是我的半完整脚本。给定一个表列表,它将尝试激活RI约束,如果它们失败,它将打印出子表中的FK数据记录,阻止它被应用。

这个项目最难的部分是FK可以是任意数量的列和任何类型,因此在这种情况下打印选择结果非常棘手(IMO)。

感谢人们提供的帮助。

cd $OGGHOME/scripts
. ./functions.sh

$ORACLE_HOME/bin/sqlplus ${ORACLE_USERID}/${ORACLE_PASSWORD}@${ORACLE_SID} << EOF 
set echo on
set feedback on
set heading off
set serveroutput on size unlimit

DECLARE 
  finalsql varchar2(2048);
  part1sql varchar2(1024) ;
  part2sql varchar2(1024) := ' ';
  cownername varchar2(1024);
  ctablename varchar2(1024);
  pownername varchar2(1024);
  ptablename  varchar2(1024);
  cnt number := 0;

  desc_tab dbms_sql.desc_tab;
  col_count INTEGER;

  cursor_name INTEGER;

  -- Weak cursor defs
  my_cursor sys_refcursor;
  col1 varchar2(50);
  d     number;
  j     number;
  lineout varchar2(2048);
  plineout varchar2(2048);
  rows number;
  eCount number := 0;


BEGIN
    FOR i in (
                select owner, table_name, constraint_name
                from dba_constraints
                where constraint_type = 'R'
                and status = 'DISABLED'
                and owner = '$DBSCHEMA'
                and TABLE_NAME in (
'RRNG_MTC_STN_CPLY',
'NRNG_MTC_VST_MTRL_USG',
'NRNG_MTC_VST',
'MTC_TSK_HRHY'))
    LOOP
        BEGIN
                dbms_output.put_line ('.');
                dbms_output.put_line ('=====================================');
                dbms_output.put('alter table '||i.owner|| '.' || i.table_name || ' enable constraint '||i.constraint_name);
                execute immediate 'alter table '||i.owner|| '.' || i.table_name || ' enable constraint '||i.constraint_name;
                dbms_output.put_line (' ... SUCCESS');

            EXCEPTION -- exception handling - dump offending data
            WHEN OTHERS THEN
            eCount := eCount + 1;
            dbms_output.put_line (' ... FAILED.  Constraint Name:  ' || i.constraint_name);

            finalsql := 'SELECT DISTINCT ';
            part1sql := '';
            part2sql := ' ';
            cnt := 0;


            for constraint in (
            SELECT      ucc1.OWNER as childowner,
                        ucc1.TABLE_NAME as childtable,
                        ucc1.column_name as childcolumn,
                        ucc2.OWNER as parentowner,
                        ucc2.TABLE_NAME as parenttable,
                        ucc2.column_name as parentcolumn,
                        utc1.data_type as childdatatype,
                        utc1.data_length as childdatalen
            FROM        all_constraints uc ,
                        all_cons_columns ucc1 ,
                        all_cons_columns ucc2,
                        all_tab_columns utc1
            WHERE       
                uc.constraint_name = ucc1.constraint_name
                AND uc.r_constraint_name = ucc2.constraint_name
                AND ucc1.POSITION        = ucc2.POSITION
                AND ucc1.table_name      = utc1.table_name
                AND ucc1.column_name     = utc1.column_name 
                AND uc.constraint_type   = 'R'
                AND uc.constraint_name   = i.constraint_name
            ORDER BY ucc1.TABLE_NAME ,
                     uc.constraint_name)
            loop
                cownername := constraint.childowner;
                ctablename := constraint.childtable;
                pownername := constraint.parentowner;
                ptablename := constraint.parenttable;
                if cnt > 0 then
                    part1sql := part1sql || ' , ';
                    part2sql := part2sql || ' AND ';
                end if;
                part1sql := part1sql || constraint.childtable || '.' || constraint.childcolumn || ' ';
                part2sql := part2sql || constraint.childtable || '.' || constraint.childcolumn || ' = ' 
                            || constraint.parenttable || '.' || constraint.parentcolumn;
                cnt := cnt + 1;
            end loop;

            finalsql := finalsql || part1sql || ' FROM ' ||  ' ' || cownername || '.' || ctablename ||  ' WHERE NOT EXISTS (SELECT 1 FROM ' || 
            pownername || '.' || ptablename || ' WHERE ' || part2sql || ') FETCH FIRST 100 rows only';


            dbms_output.put_line ('Final SQL = (' || finalsql || ')');          
--          dbms_output.put_line ('---xxx End SQL');

            lineout := 'Child Table:  ' || ctablename || '('; 
            plineout := 'Parent Table:  ' || ptablename;

            cursor_name := dbms_sql.open_cursor;
            dbms_sql.PARSE (cursor_name, finalsql, DBMS_SQL.NATIVE);

            d := dbms_sql.execute (cursor_name);


            dbms_sql.describe_columns (cursor_name, col_count, desc_tab);
            for j in 1..col_count
            LOOP
                DBMS_SQL.DEFINE_COLUMN (cursor_name, j, col1, 30);

                lineout := lineout || desc_tab(j).col_name || ' , ';
--              plineout := plineout || constraint.parentcolumn || ' ';
--              dbms_output.put_line ('Column 1: ' || j || ' is ' || desc_tab(j).col_name || ' type ' 
--                      || desc_tab(j).col_type);
            END LOOP j;
        lineout := lineout || ')';
--      plineout := plineout || ')';

        dbms_output.put_line (lineout);
        dbms_output.put_line (plineout);

        lineout := NULL;
        for j in 1..col_count
        LOOP
            if j > 1 then
                lineout := lineout || '        ';
            end if;
            lineout := lineout || desc_tab(j).col_name;
        END LOOP;

        dbms_output.put_line (lineout);

        dbms_output.put_line ('----------------------------------------');

        LOOP
            rows := dbms_sql.fetch_rows (cursor_name);
            EXIT WHEN rows = 0;
            lineout := NULL;

            for j in 1..col_count
            LOOP
                dbms_sql.column_value (cursor_name, j, col1);
                if j > 1 then
                    lineout := ltrim(lineout || '        ' || col1);
                else
                    lineout := col1;
                END IF;
            END LOOP;
            dbms_output.put_line (lineout);
        END LOOP;

        dbms_sql.close_cursor (cursor_name);
        END;
    end loop;
end;
/
EOF

答案 3 :(得分:-1)

您的FETCH FIRST 100 rows only似乎不合适。 这是PL / SQL中BULK COLLECT语句中SELECT子句的一部分;据我所知,它不是一个SQL语句的一部分,你可以传递给这样的游标 这导致游标语句无效