【问题标题】:Oracle 12c - Issue in PL/SQLOracle 12c - PL/SQL 中的问题
【发布时间】:2014-08-18 19:51:55
【问题描述】:

我有以下代码块:

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; 

我收到错误PLS-00405: SUBQUERY NOT ALLOWED IN THIS CONTEXT

如有任何帮助解决此问题,我们将不胜感激。

【问题讨论】:

  • 问题很容易发现...如果 i.id 不在(子查询)中是无效的。我认为这类似于 if exists select id from table_B where ind_valu = 'y' and i.id = b.id (但我对 12c 并不完全熟悉)。附带问题....为什么将其用作游标?一个没有循环的语句要好得多
  • pl/sql脚本中还有很多其他的使用游标的代码。应该提到这一点。
  • 你为什么首先使用 PL/SQL?这可以通过一个简单的插入语句更有效地完成:insert into val_table_err select ... from table_a where a.id not in (select id from table_b where ind_val = 'Y')

标签: sql oracle for-loop oracle12c


【解决方案1】:

在任何版本的 Oracle 中,您都不能这样做 NOT IN

NOT IN 子句放入游标定义通常是有意义的。假设 NOT IN 而不是 NOT EXISTS 是更有效的方法,这样的方法会起作用。

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');

如果您真的希望在循环内完成检查,则需要不同的构造。你可以做类似的事情

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;

当然,这不会像首先过滤掉光标中的贷款那样有效或清晰。

【讨论】:

    【解决方案2】:

    这与您的 Oracle 版本无关,我在 11g 中遇到了同样的错误,因为您不能在 IF 语句中使用 NOT IN 和子查询。

    这是我的测试用例:

    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;
    

    此匿名 pl/sql 块与您的错误相同:

    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;
    /
    

    试试这样的:

    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;
    /
    

    它的好处是让 oracle 选择连接算法,而不是自己做一个嵌套循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-29
      • 2020-06-06
      • 2014-07-23
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 2018-06-09
      • 1970-01-01
      相关资源
      最近更新 更多