如何在Oracle PL / SQL游标中找到记录数?

时间:2010-02-18 21:01:36

标签: oracle stored-procedures plsql

这是我的光标:

CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;

我立即打开光标,以便在我的程序期间锁定这些记录。

我想在有&lt;的情况下引发应用程序错误我的光标中有2条记录。使用C1%ROWCOUNT属性失败,因为它只计算到目前为止已提取的数字。

此用例的最佳模式是什么?我是否需要创建一个虚拟的MY_TABLE%ROWTYPE变量,然后遍历光标以获取它们并保持计数,或者是否有更简单的方法?如果这是这样做的方法,将取出光标中的所有行隐式关闭它,从而解锁这些行,或者它会保持打开状态,直到我明确关闭它,即使我已经全部取出它们?

我需要确保光标对于超出此计数的各种其他任务保持打开状态。

5 个答案:

答案 0 :(得分:6)

注意:我只是重读了你的问题..如果只有1条记录,你想失败。 我马上发布一个新的更新..

让我们从这里开始..

来自Oracle®DatabasePL / SQL用户指南和参考 10g第2版(10.2) 产品编号B14261-01 reference

  

打开游标时所有行都被锁定,而不是在获取它们时。提交或回滚事务时,行将被解锁。由于行不再被锁定,因此在提交后无法从FOR UPDATE游标中获取。

所以你不必担心解锁记录。

所以试试这个..

declare 
  CURSOR mytable_cur IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;

  TYPE mytable_tt IS TABLE OF mytable_cur %ROWTYPE
    INDEX BY PLS_INTEGER;

  l_my_table_recs mytable_tt;
  l_totalcount NUMBER;
begin

   OPEN mytable_cur ;
   l_totalcount := 0;

   LOOP
      FETCH mytable_cur 
      BULK COLLECT INTO l_my_table_recs LIMIT 100;

      l_totalcount := l_totalcount + NVL(l_my_table_recs.COUNT,0);

      --this is the check for only 1 row..
      EXIT WHEN l_totalcount < 2;

      FOR indx IN 1 .. l_my_table_recs.COUNT
      LOOP
         --process each record.. via l_my_table_recs (indx)

      END LOOP;

      EXIT WHEN mytable_cur%NOTFOUND;
   END LOOP;

   CLOSE mytable_cur ;
end;

替代答案 我看了你回答开始,并认为你想退出,如果有超过1行..不完全一个..所以这是我以前的答案。

仅检查1条记录的2种简单方法。

选项1 - 明确获取

declare 
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
  l_my_table_rec C1%rowtype;
  l_my_table_rec2 C1%rowtype;
begin

    open C1;
    fetch c1 into l_my_table_rec;

    if c1%NOTFOUND then
       --no data found
    end if;

    fetch c1 into l_my_table_rec2;
    if c1%FOUND THEN
      --i have more then 1 row
    end if;
    close c1;

  -- processing logic

end;

我希望你明白这一点。

选项2 - 异常捕获

declare 
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
  l_my_table_rec C1%rowtype;
begin
  begin
    select * 
      from my_table
      into l_my_table_rec
     where salary < 50000
       for update;
  exception
    when too_many_rows then
      -- handle the exception where more than one row is returned
    when no_data_found then
      -- handle the exception where no rows are returned
    when others then raise;
  end;

  -- processing logic
end;

另外 请记住:使用显式游标..您可以将光标记录中的变量%TYPE,而不是原始表格。

当您在查询中加入时,这尤其有用。

此外,请记住,您可以使用

更新表格中的行
UPDATE table_name
SET set_clause
WHERE CURRENT OF cursor_name;

类型语句,但是只有在你没有“获取”第二行的情况下我才会工作..


有关游标FOR循环的更多信息,请尝试 Here

答案 1 :(得分:1)

如果您想要在返回多行时失败,请尝试以下操作:

declare 
  l_my_table_rec my_table%rowtype;
begin
  begin
    select * 
      from my_table
      into l_my_table_rec
     where salary < 50000
       for update;
  exception
    when too_many_rows then
      -- handle the exception where more than one row is returned
    when no_data_found then
      -- handle the exception where no rows are returned
    when others then raise;
  end;

  -- processing logic
end;

答案 2 :(得分:1)

  

如果这是这样做的方法,那么   获取光标中的所有行   隐含地关闭它,从而解锁   那些行

无论何时(或是否)关闭光标,锁都将在事务持续期间出现(即直到您执行提交或回滚)。

我会去

declare
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;;
  v_1 c1%rowtype;
  v_cnt number;
begin
  open c_1;
  select count(*) into v_cnt FROM MY_TABLE WHERE SALARY < 50000 and rownum < 3;
  if v_cnt < 2 then
    raise_application_error(-20001,'...');
  end if;
  --other processing
  close c_1;
end;

在游标打开(锁定行)和​​选择计数之间,有一个很小的可能性,有人在工作表中插入一行或多行,工资低于50000.在这种情况下,应用程序错误会被提升但是光标只会处理光标打开时出现的行。如果这是一个担心,最后再次检查c_1%rowcount,如果遇到问题,则需要回滚到保存点。

答案 3 :(得分:0)

在遍历游标之前创建一个保存点,然后在找到&lt;时使用部分回滚。返回了2条记录。

答案 4 :(得分:0)

您可以启动交易并检查SELECT COUNT(*)MY_TABLE WHERE SALARY&lt; 50000大于1.