oracle 在一个过程中,一个开始结束和多个开始结束有什么区别?

oogrdqng  于 2023-03-17  发布在  Oracle
关注(0)|答案(2)|浏览(161)

我们总是在PLSQL过程中看到这种结构,但是如果我使用许多开始end,有什么区别呢?有些人喜欢写许多嵌套的BEGIN,end,而有些过程只写一对BEGIN,为什么?这就产生了另一个问题,EXCEPTION必须在END之前结束吗?如果你想在一个过程中定义多个EXCETPION,你必须定义多个BEGIN,END。

BEGIN
...
EXCEPTION WHEN .. THEN
...
END
BEGIN

begin
...
end;

begin
...
end;

...
EXCEPTION WHEN .. THEN
...
END

我想知道在许多开始结束写代码有什么好处吗?我将不胜感激,如果你能解释给我听,谢谢

gg0vcinb

gg0vcinb1#

这取决于程序做什么;有时是简单的BEGIN-EXCEPTION-END,有时是更多的BEGIN-EXCEPTION-END(包含在“主”BEGIN-END中)。
多个块的示例:

declare
  l_salary number;
begin
  -- I "hope" there's just one CLERK. If there's none or more of them, I want to handle it
  begin
    select salary into l_salary
    from emp
    where job = 'CLERK';
  exception
    when no_data_found then
      l_salary := 150;
    when too_many_rows then
      l_salary := 100;
  end;
  dbms_output.put_line('CLERK: ' || l_salary);

  -- I "hope" there's just one SALESMAN. If there's none or more of them, I want to handle it
  begin
    select salary into l_salary
    from emp
    where job = 'SALESMAN';
  exception
    when no_data_found then
      l_salary := 250;
    when too_many_rows then
      l_salary := 200;
  end;
  dbms_output.put_line('SALESMAN: ' || l_salary);
end;

如果只是一个BEGIN-END,我将无法处理两个失败的SELECT,因为我不知道 * 哪一个 * 失败了:

declare
  l_salary number;
begin
  select salary into l_salary f
  from emp 
  where job = 'CLERK';
  dbms_output.put_line('CLERK': ' || l_salary');

  select salary into l_salary f
  from emp 
  where job = 'SALESMAN';
  dbms_output.put_line('SALESMAN': ' || l_salary');

exception
  when no_data_found then
    l_salary := ???;         --> what to put here? Did CLERK's or SALESMAN's
  when too_many_rows then
    l_salary := ???;         --> what to put here?
end;

嵌套BEGIN-EXCEPTION-END的另一种用法是在循环中;如果代码(在循环中)失败,则循环停止。如果您处理错误,则让其他循环继续。当您遇到失败的面向集合的查询,并且您不知道是什么/谁造成的问题时,这一点特别有用。在循环中,您可以 * 隔离 * 它(啊哈!好了,现在我知道要修复什么了!),然后重新运行原始查询。例如:

declare
  l_salary number;
begin
  for cur_r in (select distinct job from emp) loop
    begin
      select salary into l_salary
      from emp
      where job = cur_r.job;
    exception
      when others then
        dbms_output.put_Line(cur_r.job ||': '|| sqlerrm);
    end;   
  end loop;
end;

没有它:

declare
  l_salary number;
begin
  for cur_r in (select distinct job from emp) loop
      select salary into l_salary
      from emp
      where job = cur_r.job;
  end loop;

exception
  when others then
    dbms_output.put_line('SELECT failed, but I do not know for which job and ' ||
                         ' I can not reference cur_r.job outside of the loop);
end;
fkaflof6

fkaflof62#

完整语法为

declare
    ...
begin
    ...
exception
    ...
end;

declareexception是可选的。
这些关键字本身没有任何作用,因此

begin
    do_stuff(1);

    begin
        do_stuff(2);
    end;

    do_stuff(3);
end;

是一回事

begin
    do_stuff(1);
    do_stuff(2);
    do_stuff(3);
end;

像这样的子块只有在您只想为一个特定部分执行declare操作时才有用,例如

begin
    do_stuff(1);

    declare
        some_variable_only_valid_here integer;
    begin
        do_stuff(some_variable_only_valid_here);
    end;

    do_stuff(3);
end;

或者,如果您希望某个特定步骤使用exception(这是跟踪错误详细信息的好方法-初学者的错误是编写大量杂乱无章的过程,但底部只有一个异常处理程序,这样就无法捕获足够有用的错误信息,例如确切的步骤失败或无法处理哪些参数值)。

begin
    do_stuff(1);

    begin
        how_about_we_give_this_a_try(2);
    exception
        when zero_divide then
            raise_application_error(-20123, 'Really specific details help', true);
    end;

    do_stuff(3);
end;

或者当然两者都有。
如果一个子块变得很复杂,有很多局部变量和代码行等,那么你可以考虑将它重构为一个单独的过程,例如:

begin
    do_stuff(1);

    launch_rocket_into_space(2);

    do_stuff(3);
end;

其中launch_rocket_into_space()是调用how_about_we_give_this_a_try()并处理零分频错误的过程。

相关问题