简体   繁体   中英

Oracle 12c - Issue in PL/SQL

I have the following block of code:

DECLARE
  CURSOR c_cursor IS
    SELECT *
    FROM   table_a;

    FOR i IN c_cursor LOOP
    IF i.id NOT IN (SELECT id FROM table_b WHERE ind_val='Y')
     THEN
      BEGIN
        INSERT INTO val_table_err
        VALUES (''ERROR:id''|| i.id,
                1,
                1,
                NULL,
                1,
                i.type_cd);
      END;
    END IF;
    END LOOP; 

I am getting the error PLS-00405: SUBQUERY NOT ALLOWED IN THIS CONTEXT

Any help to resolve this issue would be appreciated.

You can't do a NOT IN like that in any version of Oracle.

It would generally make sense to put the NOT IN clause into your cursor definition. Assuming that NOT IN rather than NOT EXISTS is the more efficient approach, something like this would work.

CURSOR c_cursor IS
    SELECT *
    FROM   table_a a
    WHERE  a.id NOT IN (SELECT b.id
                          FROM table_b b
                         WHERE ind_val = 'Y');

If you really want the check to be done within the loop, you'd need a different construction. You could do something like

FOR i IN c_cursor 
LOOP
  SELECT COUNT(*) 
    INTO l_cnt
    FROM table_b b
   WHERE b.id = i.id
     AND b.ind_val = 'Y';

  IF( l_cnt = 0 )
  THEN
    <<do something>>
  END IF;
END LOOP;

Of course, this won't be as efficient or as clear as filtering out the loans in the cursor in the first place.

This is nothing related to your Oracle version, I got the same error in 11g, because you can't use NOT IN and a subquery inside an IF statement.

Here's my test case:

create table table_a (idA number);
create table table_b (idB number);

insert into table_a values(1);
insert into table_a values(2);
insert into table_b values(1);
commit;

This anonymous pl/sql block gets the same error as yours:

DECLARE
  i number;
  CURSOR c_cursor IS
    SELECT idA
    FROM   table_a;
begin
    FOR i IN c_cursor LOOP
    IF i NOT IN (SELECT idB FROM table_b)
     THEN
        dbms_output.put_line(i);
    END IF;
    END LOOP; 
end;
/

Try something like this instead:

DECLARE
  CURSOR c_cursor IS
    SELECT idA, idB
    FROM   table_a a left join table_b on idA=idB;
  i c_cursor%rowtype;
begin
    FOR i IN c_cursor LOOP
    IF i.idB is null
     THEN
        dbms_output.put_line(i.idA);
    END IF;
    END LOOP; 
end;
/

It has the benefit of letting oracle choose the join algorithm, instead of doing a nested loop yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM