foreach游标显式和foreach游标隐式有什么区别

问题描述

这里有一个示例,我使用显式游标来解决任务。

set serveroutput on
DECLARE
  CURSOR c_1
  IS
    SELECT 
        LNR,LFNDNR,DATUM,STUECK,ANR
    FROM 
        lagerbuchung;
   CURSOR c_2(p_LNR INT)
   IS
    SELECT 
       ORT
    FROM 
        LAGER
    WHERE
      lager.LNR = p_LNR; 
    v_ort varchar(45);
BEGIN
  FOR v_rec IN c_1
  LOOP
    open c_2(v_rec.LNR);
    fetch c_2into v_ort;
    DBMS_OUTPUT.PUT_LINE(': ' || v_rec.LNR || ' : ' || v_rec.LFNDNR ||' : ' || v_rec.DATUM ||' : ' || v_rec.STUECK || ' : ' || v_rec.ANR || ' : ' || v_ort );
    close c_2;
  END LOOP;
END;

所以我的问题是,显式 foreach 游标和隐式 foreach 游标有什么区别?
代码相似吗?哪个更好用?我试图重现代码但使用隐式 foreach 游标,但没有管理并放弃。

解决方法

显式游标应该明确定义并声明为指向私有 SQL 区域,而隐式游标只是一条 SQL 语句,不需要任何人打开,因为它已经被数据库打开和关闭了自己的。

对于你的情况,使用这样的代码

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  v_ort varchar(45);
BEGIN
  FOR v_rec IN 
  (
    SELECT l.ort,lb.lnr,lb.lfndnr,lb.datum,lb.stueck,lb.anr
      FROM lager l
      JOIN lagerbuchung lb
     WHERE lb.lnr = l.lnr 
  )  
  LOOP
    DBMS_OUTPUT.PUT_LINE(': ' || v_rec.lnr || ' : ' || v_rec.lfndnr ||
                         ' : ' || v_rec.datum || ' : ' || v_rec.stueck ||
                         ' : ' || v_rec.anr || ' : ' || v_rec.ort);
  END LOOP;
END;

足以将当前光标转换为隐式光标

,

如果你明确为游标声明一个变量,那么这个cursor is explicit,例如:

declare
  cursor c1 is
    select 1 as n from dual;
begin
  for r in c1 loop
    dbms_output.put_line(r.n);
  end loop;
end;

如果您在代码中内联 sql 查询(在 FOR LOOPSELECT INTO 中),PLSQL 会生成隐式(内部/未声明)游标,例如:

begin
  for r in (select 1 as n from dual) loop
    dbms_output.put_line(r.n);
  end loop;
end;

显式 foreach 游标和隐式 foreach 游标有什么区别?代码类似吗?哪个更好用?

区别在于您需要为显式游标声明一个变量。您还需要打开、关闭和获取显式游标。出于这个原因,隐式游标通常会产生更整洁的代码。

仍然有显式游标的用例(参见 Practical life examples of oracle explicit cursor use):

  • 您需要在同一个 PLSQL 程序中多次重用同一个游标。使用显式游标,您可以重用变量而无需重复查询。
  • 您想通过 LIMIT 子句使用批量收集。使用显式游标,您可以直接设置限制。

我试图重现代码,但使用隐式 foreach 游标,但没有管理并放弃。

您可以使用隐式游标直接翻译您的代码:

declare
  v_ort varchar(45);
begin
  for v_rec in (SELECT LNR,LFNDNR,DATUM,STUECK,ANR FROM lagerbuchung) loop
    SELECT ORT into v_ort FROM LAGER WHERE lager.LNR = v_rec.LNR;
    DBMS_OUTPUT.PUT_LINE(': ' || v_rec.LNR || ' : ' || v_rec.LFNDNR ||
                         ' : ' || v_rec.DATUM || ' : ' || v_rec.STUECK ||
                         ' : ' || v_rec.ANR || ' : ' || v_ort);
  end loop;
end;

但是 @Barbaros Özhan 已经发布了一个使用单个查询的更高效的版本。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...