【问题标题】:Are there alternative methods for saying 'next' in a pl/sql for loop?是否有在 pl/sql for 循环中说“下一步”的替代方法?
【发布时间】:2010-09-30 13:54:59
【问题描述】:

所以我有一个处理 ID 列表的 for 循环,并且有一些相当复杂的事情要做。不涉及所有丑陋的细节,基本上是这样的:

宣布 l_selected APEX_APPLICATION_GLOBAL.VC_ARR2; ……剪…… 开始 -- 获取列表ID l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST); -- 在一个很好的循环中处理每个 FOR i IN 1..l_selected.count 环形 - 做一些数据检查的东西...... -- 在这里我们将寻找重复的条目,所以如果发现重复我们可以 noop 开始 从 org_county_accountable 中选择county_id 到v_dup_check 其中organization_id = :P4_ID AND County_id = v_county_id; - 下一个;!不;!但没有下一个! 当 NO_DATA_FOUND THEN 时出现异常 dbms_output.put_line('没有找到副本,继续'); 结尾; -- 这里有我们只想在没有欺骗的情况下执行的代码 如果 v_dup_check 为空 那么 -- 如果不是重复记录,请继续... 别的 -- 重置重复检查变量 v_dup_check := NULL; 结尾; 结束循环; 结尾;

我通常如何处理这个问题是通过选择一个值,然后将以下代码包装在 IF 语句中检查以确保重复检查变量为 NULL。但这很烦人。我只想说NEXT;或 NOOP;或者其他的东西。特别是因为我已经必须捕获 NO_DATA_FOUND 异常。我想我可以给 Oracle 写一封信,但我很好奇其他人是如何处理这件事的。

我也可以将它包装在一个函数中,但我正在寻找更清洁/更简单的东西。

【问题讨论】:

  • 很高兴看到其他人在使用 APEX!
  • APEX 摇滚,伙计 ;-) forums.oracle.com 上的论坛真的很有帮助。
  • 在您的问题以及 tuinstoel 和 Pourquoi 的解决方案中,您在 FOR 循环的每次迭代中都执行了一个额外的 SQL 查询(以及与 PL/SQL 的上下文切换)......这不一定便宜的。如果性能是一个问题,最好在单个查询中预先删除所有重复。
  • jimmyorr,这是一个非常好的观点,先生。

标签: oracle plsql controls for-loop


【解决方案1】:

这是 GOTO 语句可能有用的情况。请参阅控制结构中的Oracle Documentation 以了解如何执行此操作。此外,您可能想在此处搜索以了解如何查询记录的存在。运行查询并等待异常并不是最佳选择。

【讨论】:

  • 这实际上是一个非常严格的解决方案,GOTO 语句,谢谢!我不太明白你的其余答案。我很乐意查询重复记录,这是必要的。虽然,我更喜欢选择计数的想法,因为不会抛出异常。
【解决方案2】:

与其捕获NO_DATA_FOUND,不如将​​匹配条目的数量选择到一个变量中,比如l_count,如果这个计数为零,如何继续?类似于以下内容:

宣布 l_selected APEX_APPLICATION_GLOBAL.VC_ARR2; l_count 整数; ……剪…… 开始 -- 获取列表ID l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST); -- 在一个很好的循环中处理每个 FOR i IN 1..l_selected.count 环形 - 做一些数据检查的东西...... -- 这里我们将计算重复的条目,所以如果发现重复我们可以 noop 从 org_county_accountable 中选择 COUNT(*) 到 l_count 其中organization_id = :P4_ID AND County_id = v_county_id; 如果 l_count = 0 那么 -- 这里有我们只想在没有欺骗的情况下执行的代码 -- 如果不是重复记录,请继续... 万一; 结束循环; 结尾;

【讨论】:

  • 正要写同样的东西
【解决方案3】:

Oracle 11g 向 PL/SQL 中添加了 C 风格的“继续”循环结构,这在语法上听起来像您正在寻找的。​​p>

出于您的目的,为什么不在进入循环之前消除重复项?这可以通过使用表函数查询 l_selected 来完成,然后过滤掉您不想要的记录,而不是遍历 每个 值。比如……

declare

l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;

cursor no_dups_cur (p_selected APEX_APPLICATION_GLOBAL.VC_ARR2) is 
  select * from (
  select selected.*, 
         count(*) over (partition by county_id) cnt -- analytic to find counts grouped by county_id
    from table(p_selected) selected -- use table function to treat VC_ARR2 like a table 
    ) where cnt = 1 -- remove records that have duplicate county_ids
    ;

begin

l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);

for i in no_dups_cur(l_selected) loop

  null; -- do whatever to non-duplicates 

end loop;

end;

只需用您自己的逻辑替换确定“重复”的逻辑(您的示例中没有足够的信息来真正回答该部分)

【讨论】:

    【解决方案4】:

    也可以计算行数(请参阅 Pourquoi Litytestdata),但您也可以在 when_no_data_found exception 块中做您想做的事情。

    declare 
      l_selected    apex_application_global.vc_arr2;
      l_county_id   org_county_accountable.count_id%type;
    begin
      l_selected := apex_util.string_to_table(:p4_select_lst);
      for i in l_selected.first..l_selected.last loop
        begin
          select count_id
          into   l_county_id
          from   org_county_accountable
          where  organization_id = :p4_id
          and    county_id       = v_county_id;
        exception
          when no_data_found then 
            -- here we have code we only want to execute if there are no dupes already
            -- if not a duplicate record, proceed...
        end;
      end loop;
    end;
    

    【讨论】:

      【解决方案5】:

      另一种方式 - 将检查变成本地函数:

      DECLARE
        l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
      
        ...snip...
        FUNCTION dup_exists 
           ( p_org_id org_county_accountable.organization_id%TYPE
           , p_county_id org_county_accountable.county_id%TYPE
           ) RETURN BOOLEAN 
        IS
          v_dup_check org_county_accountable.county_id%TYPE;
        BEGIN
          SELECT county_id INTO v_dup_check FROM org_county_accountable
          WHERE organization_id = p_org_id AND county_id = p_county_id;
          RETURN TRUE;
        EXCEPTION WHEN NO_DATA_FOUND THEN
          RETURN FALSE;
        END;
      BEGIN
      
        -- get the list ids
        l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
        -- process each in a nice loop
        FOR i IN 1..l_selected.count
        LOOP
          -- do some data checking stuff...
      
          -- here we have code we only want to execute if there are no dupes already
          IF NOT dup_exists (:P4_ID, v_county_id) THEN
            -- if not a duplicate record, proceed...
      
          END;
        END LOOP;
      END;
      

      当然,如果您愿意,可以重写本地函数以使用 count 方法:

        FUNCTION dup_exists 
           ( p_org_id org_county_accountable.organization_id%TYPE
           , p_county_id org_county_accountable.county_id%TYPE
           ) RETURN BOOLEAN 
        IS
          l_count INTEGER;
        BEGIN
           SELECT COUNT(*) INTO l_count 
             FROM org_county_accountable
            WHERE organization_id = p_org_id AND county_id = p_county_id;
           RETURN (l_count > 0);
        END;
      

      【讨论】:

        【解决方案6】:

        另一种方法是引发和处理用户定义的异常:

        DECLARE
          l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
          duplicate_org_county EXCEPTION;
        
          ...snip...
        BEGIN
        
          -- get the list ids
          l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
          -- process each in a nice loop
          FOR i IN 1..l_selected.count 
          LOOP
            BEGIN
              -- do some data checking stuff...
        
              -- here we will look for duplicate entries, so we can noop if duplicate is found
              BEGIN
                SELECT county_id INTO v_dup_check FROM org_county_accountable
                WHERE organization_id = :P4_ID AND county_id = v_county_id;
                RAISE duplicate_org_county;
              EXCEPTION WHEN NO_DATA_FOUND THEN
                dbms_output.put_line('no dups found, proceeding');
              END;
              -- here we have code we only want to execute if there are no dupes already
        
            EXCEPTION
              WHEN duplicate_org_county THEN NULL;
            END;
          END LOOP;
        END;
        

        我通常不会这样做,但如果有六个理由跳转到下一条记录,这可能比多个嵌套的 IF 更可取。

        【讨论】:

          【解决方案7】:
          <xmp>
          <<next_loop>>
          loop
          ...
          ...
          if ....
          then
             goto next_loop;
          
          </xmp>
          

          【讨论】:

            【解决方案8】:

            我知道这是一个老歌,但我不禁注意到上面的答案都没有考虑到光标attributes

            有四个与游标相关的属性:ISOPEN、FOUND、NOTFOUND 和 ROWCOUNT。可以使用 % 分隔符访问这些属性,以获取有关游标状态的信息。

            游标属性的语法是:

            cursor_name%attribute
            

            其中 cursor_name 是显式游标的名称。

            因此,在这种情况下,您可以使用 ROWCOUNT(表示到目前为止已获取的行数)来满足您的目的,如下所示:

            declare 
               aux number(10) := 0;
               CURSOR cursor_name is select * from table where something;
            begin
                 select count(*) into aux from table where something;
                 FOR row IN cursor_name LOOP
                    IF(aux > cursor_name%ROWCOUNT) THEN 'do something is not over';
                    ELSE 'do something else';
                    END IF;
                 END LOOP;
            end;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-01-18
              • 1970-01-01
              • 1970-01-01
              • 2017-07-30
              • 1970-01-01
              • 2013-08-29
              • 2020-12-04
              相关资源
              最近更新 更多