plsql中游标内部的For循环

plsql中游标内部的For循环,sql,plsql,Sql,Plsql,我有一个包裹: create or replace package body package_name as procedure update_dte cursor cur_variable is select person_id, eff_start_date, eff_end_date from tab_abc; begin open cursor cur_variable; loop num_count := cur_variable%ROWCOUNT; for i in 1.

我有一个包裹:

create or replace package body package_name
as 
procedure 
update_dte
cursor cur_variable is 
select person_id, eff_start_date, eff_end_date from tab_abc;

begin

open cursor cur_variable;
loop
num_count := cur_variable%ROWCOUNT;

for i in 1..num_count
loop
fetch cursor cur_variable
into l_person_id, l_eff_start_date, l_eff_end_date;

update tab_abc
set l_eff_start_date='31-dec-4712'
where person_id=l_person_id;
end loop;
end loop;
close cur_variable;

end;
end;
/

我在游标循环中使用for循环的查询将进入无止境循环。基本上,我希望遍历光标直到其行计数,这样就不会错过更新的迭代。

原因很明显:您没有退出条件。另外,我不太明白为什么需要两个循环。那么您只需要一个内部循环

添加一个退出条件(尽管不记得确切的语法),如下所示:

EXIT WHEN cur_variable%NOT_FOUND ;
这应该在
提取之后立即执行


顺便说一下,您不需要检查记录的数量。只要循环(永远)并在不再从
获取返回结果时退出即可。原因很明显:您没有退出条件。另外,我不太明白为什么需要两个循环。那么您只需要一个内部循环

添加一个退出条件(尽管不记得确切的语法),如下所示:

EXIT WHEN cur_variable%NOT_FOUND ;
这应该在
提取之后立即执行


顺便说一下,您不需要检查记录的数量。只要循环(永远)并在不再从
获取返回结果时退出,您的代码就不会像您期望的那样工作,因为a)您缺少外部循环中的exit子句,b)在至少获取行之前,%行计数将返回0(即使它已经获取了一行,如果您希望它返回游标中的行数,那么您就大错特错了——我们只有在从游标中获取完所有行后才能知道游标返回的行数),c)使用
l_eff_start_date='31-dec-4712'
您试图将变量设置为update语句的一部分-这没有意义d)您没有声明l_person_id、l_eff_start_date、l_eff_end_date或num_count变量

您有一些选择-首先,这里是您的代码应该是什么样子-您根本不需要外部循环:

create or replace package body package_name
as 
  procedure update_dte
  is

    cursor cur_variable is 
    select person_id, eff_start_date, eff_end_date
    from   tab_abc;

  begin
    open cursor cur_variable;
    loop
      fetch cursor cur_variable
      into l_person_id, l_eff_start_date, l_eff_end_date;

      exit when cur_variable%notfound;

      update tab_abc
      set    start_date = to_date('31-12-4712', 'dd-mm-yyyy') -- assuming start_date is of DATE datatype;
      where  person_id=l_person_id;
    end loop;

    close cur_variable;

  end update_dte;
end package_name;
/
但是,有一种更简单的方法可以在游标中循环,您不必担心创建一个变量来向其中返回值、打开或关闭游标或获取记录—循环游标将为您处理所有这些:

create or replace package body package_name
as 
  procedure update_dte
  is

    cursor cur_variable is 
    select person_id, eff_start_date, eff_end_date
    from   tab_abc;

  begin
    for rec in cur_variable;
    loop
      update tab_abc
      set    start_date = to_date('31-12-4712', 'dd-mm-yyyy') -- assuming start_date is of DATE datatype;
      where  person_id=l_person_id;
    end loop;
  end update_dte;
end package_name;
/
然而,更好、更高效的方法是使用一个update语句一次性完成工作,而不是一行一行地完成。在您的情况下,您甚至不需要光标循环,因为您正在更新tab_abc中的所有行,所以您的更新变得简单:

create or replace package body package_name
as 
  procedure update_dte
  is
  begin
    update tab_abc
    set    start_date = to_date('31-12-4712', 'dd-mm-yyyy'); -- assuming start_date is of DATE datatype;
  end update_dte;
end package_name;
/

在这三种情况下,我都假设您试图更新start_date列(并且它是日期数据类型)。如果情况并非如此,您需要更新您的问题,以包含更多关于您试图使用此过程执行的操作的详细信息。这是一个家庭作业问题吗?

您的代码没有按预期工作,因为a)您缺少外部循环中的exit子句,b)在至少获取了行之前,%ROWCOUNT将返回0(即使它已经获取了一行,如果您希望它返回游标中的行数,那么您就大错特错了——我们只有在从游标中获取完所有行后才能知道游标返回的行数),c)使用
l_eff_start_date='31-dec-4712'
您试图将变量设置为update语句的一部分-这没有意义d)您没有声明l_person_id、l_eff_start_date、l_eff_end_date或num_count变量

您有一些选择-首先,这里是您的代码应该是什么样子-您根本不需要外部循环:

create or replace package body package_name
as 
  procedure update_dte
  is

    cursor cur_variable is 
    select person_id, eff_start_date, eff_end_date
    from   tab_abc;

  begin
    open cursor cur_variable;
    loop
      fetch cursor cur_variable
      into l_person_id, l_eff_start_date, l_eff_end_date;

      exit when cur_variable%notfound;

      update tab_abc
      set    start_date = to_date('31-12-4712', 'dd-mm-yyyy') -- assuming start_date is of DATE datatype;
      where  person_id=l_person_id;
    end loop;

    close cur_variable;

  end update_dte;
end package_name;
/
但是,有一种更简单的方法可以在游标中循环,您不必担心创建一个变量来向其中返回值、打开或关闭游标或获取记录—循环游标将为您处理所有这些:

create or replace package body package_name
as 
  procedure update_dte
  is

    cursor cur_variable is 
    select person_id, eff_start_date, eff_end_date
    from   tab_abc;

  begin
    for rec in cur_variable;
    loop
      update tab_abc
      set    start_date = to_date('31-12-4712', 'dd-mm-yyyy') -- assuming start_date is of DATE datatype;
      where  person_id=l_person_id;
    end loop;
  end update_dte;
end package_name;
/
然而,更好、更高效的方法是使用一个update语句一次性完成工作,而不是一行一行地完成。在您的情况下,您甚至不需要光标循环,因为您正在更新tab_abc中的所有行,所以您的更新变得简单:

create or replace package body package_name
as 
  procedure update_dte
  is
  begin
    update tab_abc
    set    start_date = to_date('31-12-4712', 'dd-mm-yyyy'); -- assuming start_date is of DATE datatype;
  end update_dte;
end package_name;
/

在这三种情况下,我都假设您试图更新start_date列(并且它是日期数据类型)。如果情况并非如此,您需要更新您的问题,以包含更多关于您试图使用此过程执行的操作的详细信息。这是一个家庭作业问题吗?

事实上,问题是外部循环中没有exit语句-游标永远不会从中提取,因为
num\u count:=cur\u变量%ROWCOUNT
将始终为0。这就是为什么我写您删除循环中的计数器,并且只检查光标是否返回结束数据条件以退出循环(顺便说一句,我还提到您的代码中缺少该条件)。我不是OP。但我接受您的观点;我忽略了一个事实,即你第一句话中缺失的退出声明与你的示例退出声明不同;我的错-对不起!没问题。别担心。事实上,问题是外部循环中没有exit语句-游标永远不会从中提取,因为
num\u count:=cur\u变量%ROWCOUNT
将始终为0。这就是为什么我写您删除循环中的计数器,并且只检查光标是否返回结束数据条件以退出循环(顺便说一句,我还提到您的代码中缺少该条件)。我不是OP。但我接受您的观点;我忽略了一个事实,即你第一句话中缺失的退出声明与你的示例退出声明不同;我的错-对不起!没问题。别担心。你为什么要首先使用游标和for循环?似乎没有必要为什么要首先使用游标和for循环?似乎没有必要