2010-02-18 27 views
8

这里是我的光标:如何查找Oracle PL/SQL游标中的记录数量?

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

我立即以锁定这些记录我的过程期间打开游标。

我想提出一个应用程序错误,如果我的光标有2条记录。使用C1%ROWCOUNT属性失败,因为它只计算迄今为止已获取的数量。

这个用例的最佳模式是什么?我是否需要创建一个虚拟的MY_TABLE%ROWTYPE变量,然后通过光标循环来获取它们并保留一个计数,或者有更简单的方法吗?如果这是做到这一点的方法,那么将获取我游标中的所有行隐式关闭它,从而解锁这些行,或者保持打开状态直到我明确地关闭它,即使我已经将它们全部提取出来了。

我需要确保游标保持打开状态,以便执行超出此计数的各种其他任务。

回答

6

NB:我刚才重读你的问题..你要失败的。如果只有1个记录.. 我会后在某一时刻有新的更新..

,让我们开始在这里..

的Oracle®数据库PL/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; 

ALTERNATE ANSWER 我看了你的答案向后启动,以为你想退出,如果有更多的则1排..不是正好有一个。所以这是我以前的答案。

2个简单的方法来检查只有1条记录。

选项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; 

此外 记住:用显式游标..你可以%键入您的变量关闭光标记录而不是原始表。

当您在查询中加入时,这特别有用。

此外,rememebr您可以用

UPDATE table_name 
SET set_clause 
WHERE CURRENT OF cursor_name; 

类型语句更新表中的行,但我认为如果你还没有“获取”第二行只会工作..


有关游标FOR循环一些更多的信息.​​.尝试 Here

+0

感谢全面的答案。我希望有可能是一个更简单的方式来获得的光标记录的计数而不实际获取的所有数据,但我更喜欢这种解决方案在出台保存点。将一堆记录读入我没有用的变量中感觉很笨拙(这实际上只是一个锁,我需要知道我锁定了多少记录)。我的使用案例是我需要删除一个记录,但必须总是剩下一个;在我确认2存在于我的光标后,我发出一个单独的删除来查明我想删除的特定记录。 – 2010-02-19 14:36:38

+0

好吧..也许你应该尝试反向..和只是一个直上“重复”的行删除。如果他们不存在..然后什么也没有发生。如果他们这样做,你留下1? ..即DELETE FROM my_table WHERE(这里只选择重复的行); – ShoeLace 2010-02-22 22:54:18

0

在遍历游标之前创建保存点,然后在发现有2条记录返回时使用部分回滚。

0

您就可以开始交易,并检查是否SELECT COUNT(*)MY_TABLE WHERE SALARY < 50000大于1

1

如果你正在寻找失败whenver你有超过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; 
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; 

有一个很小的机会,之间的时间打开游标(锁定行)和​​SELECT COUNT,有人插入一个或多个行到一个表薪金低于50000.在这种情况下,应用程序错误会被提高,但游标只会处理打开游标时出现的行。如果这是一个担心,最后再对c_1%rowcount进行检查,如果遇到问题,则需要回滚到保存点。