这是我的光标:
CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
我立即打开光标,以便在我的程序期间锁定这些记录。
我想在有&lt;的情况下引发应用程序错误我的光标中有2条记录。使用C1%ROWCOUNT属性失败,因为它只计算到目前为止已提取的数字。
此用例的最佳模式是什么?我是否需要创建一个虚拟的MY_TABLE%ROWTYPE变量,然后遍历光标以获取它们并保持计数,或者是否有更简单的方法?如果这是这样做的方法,将取出光标中的所有行隐式关闭它,从而解锁这些行,或者它会保持打开状态,直到我明确关闭它,即使我已经全部取出它们?
我需要确保光标对于超出此计数的各种其他任务保持打开状态。
答案 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.