PL/SQL 中的 for 循环和列

Posted

技术标签:

【中文标题】PL/SQL 中的 for 循环和列【英文标题】:For loop and columns in PL/SQL 【发布时间】:2011-10-26 10:48:19 【问题描述】:

我是 PL/SQL 的新手。我对这种语言的循环有疑问。我想做这样的循环:

FOR nr IN 1..102 
LOOP
  DBMS_OUTPUT.PUT_LINE(nr);
  IF rec.column_||nr IS NULL
    THEN
    DBMS_OUTPUT.PUT_LINE('test');
  END IF;
END LOOP;

我已经创建了一个游标。如您所见,我想检查名称列从 column_1 到 column_102 的所有列。不幸的是||运算符不适用于这种情况。 你知道我的问题的一些解决方案吗?

【问题讨论】:

【参考方案1】:

您可以使用dynamic PL/SQL 执行此操作。使用 EXECUTE IMMEDIATE 语句将字符串参数作为 PL/SQL 执行,您可以按照问题中的意图使用 || 来弥补。

例子:

BEGIN 
    FOR nr IN 1..102 
    LOOP
        DBMS_OUTPUT.PUT_LINE(nr);
        EXECUTE IMMEDIATE 
            'BEGIN ' || 
            'IF rec.column.' || nr ||' is null THEN ' ||
                'DBMS_OUTPUT.PUT_LINE(''test''); ' ||
            'END IF; ' || 
            'END; ';
    END LOOP;
END;

或者您也可以将rec.column.' || nr ||' is null 分配给一个变量,并将PUT_LINE 置于EXECUTE IMMEDIATE 部分之外:

更新:似乎无法绑定BOOLEAN 变量,所以我修改了示例以使用NUMBER

更新 2: 可能会提高效率,但可能不适合这种情况。对动态 SQL 使用常量 VARCHAR,并使用绑定变量传入 nr。如果在大循环中,这甚至比使用本机 SQL 更有效。不过,我认为 'rec.column.:arg is null 不会像 'rec.column.1 is null 一样执行。

 DECLARE
    isnull NUMBER;
 BEGIN 
    FOR nr IN 1..102 
    LOOP
        DBMS_OUTPUT.PUT_LINE(nr);
        EXECUTE IMMEDIATE 
            'BEGIN ' || 
                'IF rec.column.' || nr ||' IS NULL THEN ' || 
                    ':x:=1; ' || 
                'ELSE ' ||
                    ':x:=0; ' ||
                'END IF; ' ||
            'END; ' 
            USING OUT isnull;
        IF isnull = 1 THEN 
            DBMS_OUTPUT.PUT_LINE('test');
        END IF;
    END LOOP;
END;

更新 3: 看到:

无法在动态 SQL 语句中访问rec,因为它未定义(超出范围),

似乎不可能将非 sql 类型作为参数传递给动态语句(记录、游标)

一种可能的解决方法是将一些id列(SQL类型)绑定到动态语句,并使用select子句来判断当前列是否为空:

DECLARE
        isnull NUMBER;
        rec_id NUMBER; -- Identifier of the fetched record
     BEGIN 
        rec_id := rec.id;
        FOR nr IN 1..102 
        LOOP
            DBMS_OUTPUT.PUT_LINE(nr);
            EXECUTE IMMEDIATE 
                'SELECT 1 FROM my_table WHERE id = :idarg ' ||
                   ' AND column_' || nr || ' IS NULL'
              INTO isnull USING rec_id;
            IF isnull = 1 THEN 
                DBMS_OUTPUT.PUT_LINE('test');
            END IF;
        END LOOP;
    END;

【讨论】:

你能举个例子吗? 不幸的是 BOOLEAN 不是 sql 类型,因此我得到一个错误。 是的,你是对的,正如here 所解释的那样。我只是在测试时发现了这一点。我已将示例更新为使用 NUMBER 我现在有另一个问题,也许你也可以帮助我。当我尝试使用上述代码运行我的程序时。我收到此错误:PLS-00201:必须声明标识符“rec.column_1”。此问题出现在“EXECUTE IMMEDIATE...”行中 发生此错误是因为 rec 未定义且超出动态 SQL 的范围。据我所知,它没有简单的解决方法,也许您应该将某种标识符(带有 SQL 类型)绑定到动态 SQL 并使用 select 子句。查看更新后的答案,让我知道这是否适合您。

以上是关于PL/SQL 中的 for 循环和列的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在 PL/SQL 中的 for 循环没有打印出最后一次迭代

oracle 11g 中 for 循环中的 PL/SQL 限制

Oracle PL/SQL 中的 for 循环后变量丢失值

读取 XML 格式的字符串并使用 PL SQL 中的 for 循环进行更新

oracle pl/sql中的循环及if语句

PL/SQL 在 for 循环中执行即时异常处理