For循环不打印游标中的最后一条记录
Posted
技术标签:
【中文标题】For循环不打印游标中的最后一条记录【英文标题】:For loop not printing last record in a cursor 【发布时间】:2021-06-30 08:41:22 【问题描述】:所以,我正在使用游标,游标最初使用初始 for 循环运行,现在如果游标中的记录数超过一个,我需要执行操作,所以我首先获取记录数并存储在一个变量中并使用基于此的if条件。现在问题是当我运行整个过程时,该过程完成了它的工作,但只针对游标中的第一条记录并完全跳过第二条记录。请建议或帮助我找出错误。 添加代码sn-p。
for m in get_m_p(a,b)--主光标
循环 将get_m_p取入c_m;
g_m_p%notfound 时退出;
结束循环;
临时计数:= g_m_p%ROWCOUNT:
声明---
if(tempcount>1) 那么
声明----
如果结束;
结束循环;
对于两条记录,主光标在第一行返回,只对第一条进行操作,第二条记录被完全跳过。
【问题讨论】:
【参考方案1】:这是多余的一行:
fetch get_m_p into c_m;
您不会在游标 FOR 循环中显式获取,而是在每次循环迭代中隐式完成。删除该行。
如何获取游标返回的行数?幸运的是,您似乎并不关心它是否返回了多少行(确切地说)。您只想知道它是否返回超过 1 行。所以,从字面上算数;如果计数器超过 1,则退出循环。
SQL> DECLARE
2 CURSOR get_m_p IS
3 SELECT *
4 FROM emp
5 WHERE deptno = 10;
6
7 l_cnt NUMBER := 0;
8 BEGIN
9 FOR m IN get_m_p
10 LOOP
11 l_cnt := l_cnt + 1;
12 EXIT WHEN l_cnt > 1;
13 END LOOP;
14
15 DBMS_OUTPUT.put_line ('Cursor returned at least ' || l_cnt || ' row(s)');
16
17 IF l_cnt > 1
18 THEN
19 NULL;
20 -- the rest of statements go here
21 END IF;
22 END;
23 /
Cursor returned at least 2 row(s)
PL/SQL procedure successfully completed.
SQL>
由于无法知道游标将返回多少行,很遗憾,您必须先检查一下,然后再决定如何处理结果。
DECLARE
CURSOR get_m_p IS
SELECT *
FROM emp
WHERE deptno = 10;
l_cnt NUMBER := 0;
BEGIN
SELECT COUNT (*)
INTO l_cnt
FROM (-- this is cursor's SELECT statement
SELECT *
FROM emp
WHERE deptno = 10);
FOR m IN get_m_p
LOOP
-- some statements here
IF l_cnt > 1
THEN
NULL;
-- statements to be executed if cursor return more than 1 row
END IF;
END LOOP;
END;
/
【讨论】:
好的,那我如何获得行数呢?最初我只使用了rowcount,没有使用整个loop-fetch-exit部分,但是它跳过了第一条记录的if条件。我了解到rowcount在获取之前第一次返回0,所以想这可能是问题并添加了那部分。 通过计数。我添加了更多信息,看看。 是的,看到了,明白了,但是if部分每次都需要执行,所以它需要在循环中,现在问题是如果我这样做,第一次计数仍然为 1,因此将跳过 if 部分,第二次开始这将起作用。这就是为什么我每次都试图获取游标中的总行数而不是通过迭代。所以每次都会检查条件,就好像我在为保证游标返回多于 1 行的特定情况执行此操作。因此,如果游标返回 2 行,则每行需要执行 if 部分。 但是同样的事情也将用于光标将返回一条记录的情况,因此 if 部分不需要执行,因此添加了特定条件。 我明白了;我再次编辑了答案,看看是否有帮助。【参考方案2】:光标:
Oracle创建内存区域来处理SQL语句,称为上下文区域,游标是指向上下文区域的指针。游标保存 SQL 语句返回的行(一个或多个)。游标所持有的行集称为活动集。
有两种类型的光标
1. Implicit cursor
2. Explicit cursor
隐式游标:
每当执行 SQL 语句时,Oracle 都会自动创建隐式游标。任何 SQL 游标属性都将作为 sql%attribute_name 访问,如下面的示例所示。使用 SQL%ROWCOUNT 属性确定受影响的行数
DECLARE
no_of_records number(2);
BEGIN
select * from records;
IF sql%notfound THEN
dbms_output.put_line('no records present');
ELSIF sql%found THEN
no_of_records := sql%rowcount;
IF no_of_records > 1 THEN
dbms_output.put_line('no of records ' || no_of_records);
END IF
END IF;
END;
显式游标:
显式游标是程序员定义的游标,用于获得对上下文区域的更多控制。应在 PL/SQL 块的声明部分中定义显式游标。它是在返回多行的 SELECT 语句上创建的。
请看下面的例子:
DECLARE
r_id records.id%type;
CURSOR c_records is
SELECT id FROM records;
BEGIN
OPEN c_records;
LOOP
FETCH c_records into r_id;
EXIT WHEN c_records%notfound;
dbms_output.put_line('Record id ' || r_id );
END LOOP;
CLOSE c_records;
END;
参考: https://www.tutorialspoint.com/plsql/plsql_cursors.htm
【讨论】:
【参考方案3】:作为替代方案,您可以缓存每一行并在之后处理。 在 Oracle 11g Express Edition 上使用示例模式“HR”的示例:
DECLARE
CURSOR get_m_p
IS
SELECT *
FROM hr.employees
WHERE department_id = 60
order by employee_id;
--
rcEmp_last get_m_p%rowtype;
l_cnt NUMBER;
BEGIN
FOR rcM IN get_m_p LOOP
l_cnt := get_m_p%rowcount;
Dbms_Output.Put_Line('l_cnt='||l_cnt);
if l_cnt=1 then
rcEmp_last:=rcM;
Else
Dbms_Output.Put_Line('Process='||to_char(l_cnt-1));
Dbms_Output.Put_Line('rcEmp_last.employee_id='||rcEmp_last.employee_id);
--
rcEmp_last:=rcM;
END IF;
End loop;
--
Dbms_Output.Put_Line('Exited FOR-LOOP');
Dbms_Output.Put_Line('l_cnt='||l_cnt);
--
if l_cnt>1 then
Dbms_Output.Put_Line('rcEmp_last.employee_id='||rcEmp_last.employee_id);
End if;
END;
输出:
文字
PL/SQL block, executed in 1 ms
l_cnt=1
l_cnt=2
Process=1
rcEmp_last.employee_id=103
l_cnt=3
Process=2
rcEmp_last.employee_id=104
l_cnt=4
Process=3
rcEmp_last.employee_id=105
l_cnt=5
Process=4
rcEmp_last.employee_id=106
Exited FOR-LOOP
l_cnt=5
rcEmp_last.employee_id=107
Total execution time 35 ms
【讨论】:
以上是关于For循环不打印游标中的最后一条记录的主要内容,如果未能解决你的问题,请参考以下文章