2017-05-28 2 views
0

Grundsätzlich ist ein Cursor ein Bereich des Speichers, der zum Speichern des Ergebnisses einer bestimmten Abfrage verwendet wird. Eine Frage, die ich habe, ist Cursor implizit durchlaufen alle Datensätze? Angenommen, ich einen Code-Schnipsel wie das schreiben folgendes:Schleifen in Cursoren in Oracle pl/sql

declare 
    cursor cur_dum is 
     select name,class,enroll_id from table_student; 
begin 
    fetch cur_dum into the_name, the_class, the_enroll_id; 

    update table_log set statement = the_name || '-'||'-'||to_char(the_enroll_id) 
    where roll_id = the_enroll_id; 

    close cur_dum; 
end; 

Wird dieser Code-Schnipsel, ohne explizite Anweisung der Schleife, automatisch eine Schleife durch alle Datensätze in table_student und führen Sie die entsprechende Update in table_log Muss ich hinzufügen müssen? eine Schleife nach der Fetch-Anweisung? Welchen Unterschied würde es machen, wenn ich während des Abrufens eine Bulk Collect-Anweisung verwende?

Aus der Antwort, ich habe es, dass explizit eine Schleife erforderlich ist.

ich auf einen Ausschnitt des Codes kam, die eine Schleife für einen Cursor verwendet, und verwendete auch eine für Innere Schleife .Der folgende ist das Codefragment: hat

Cursor CurSquirell IS 
    select Name,a_val,b_val,col_ID from table_temp; 
BEGIN 
    LoopCounter := 0; 
    commit; 
    LOOP 
     FETCH CurSquirell BULK COLLECT INTO my_name,my_a_val,my_b_val,my_col_id LIMIT 1000; 
     LoopCounter := LoopCounter + 1; 
     FOR intIndex IN 1 .. my_col_id.COUNT LOOP 
      counter := counter +1; 
      BEGIN 
      select t.tender_val,t.tender_pay, t.page_no, t.loc 
      into my_tender_val,my_tender_pay,my_page_no , my_loc 
      from bussiness_trans bt, tender_details t 
      where t.account_no = bt.account_no 
      and bt.external_id=my_col_id(intIndex) 
      and trim(replace(t.tender_pay,'0',' ')) = trim(replace(a_val(intIndex),'0',' ')) 
      and bt.id_type=1; 
      BEGIN 
       select pp.lock_id into my__lock_id 
       from pay_roll pp 
       where pp.pay_points= my_tender_pay 
       and bt.id_type=5; 
       BEGIN 
       update tab_cross_exchange tce 
       set  tce.cross_b_val = my_b_val(intIndex) 
       where tce.lock_id = my_lock_id; 
..............................sql statements... 

...sql statements... 

     end; 
    end; 
    end; 

Wenn in der Codeschleife bereits verwendet Um die Datensätze einzeln durchzugehen, warum wurde die for loop verwendet? In welchen Situationen würden Sie eine for loop so in einer Cursorschleife benötigen? Muss die Massensammlung irgendetwas tun, um die Verwendung der For-Schleife zu erzwingen?

+1

Nein, sie holen nicht implizit alle Zeilen. Sie müssten einen Bulk-Fetch oder eine Loop durchführen, wie [dokumentiert] (http://docs.oracle.com/database/121/LNPLS/cursor_for_loop_statement.htm). –

+0

Außerdem speichert ein Cursor das Ergebnis einer Abfrage nicht. Es [speichert Informationen zur Verarbeitung einer Abfrage] (http://docs.oracle.com/database/121/LNPLS/explicit_cursor.htm). Die Ergebnisse werden zurück zum Anrufer gestreamt. –

+1

Das viele verschachtelte BEGIN..END-Blöcke ist ein Code-Geruch. Ich weiß nicht, wo Sie "einen Code-Ausschnitt gefunden haben", aber ich würde das als eine Quelle guter Praxis misstrauen. – APC

Antwort

1

„ein Cursor ist ein Bereich des Speichers, der das Ergebnis einer bestimmten Abfrage zu speichern, verwendet wird“

Nicht ganz. Ein Cursor ist ein Zeiger auf einen Speicherbereich, der zum Speichern von Informationen über eine Abfrage verwendet wird. Ergebnisse der Abfrage werden in anderen Speicherbereichen gespeichert.

Die von Ihnen verwendete PL/SQL-Syntax gibt eine Variable an, die eine Abfrage definiert. die Abfrage, die Sie brauchen, um

  1. Öffnen Sie den Cursor
  2. Fetch die Daten in Zielvariable (n)
  3. Wenn Sie fertig sind, schließen Sie den Cursor

Jede holen gibt eine Zeile auszuführen. Um die Abfrage zu erschöpfen, müssen Sie den Abruf in einer Schleife ausführen. Dies ist die ausführliche Art und Weise, dies zu tun:

declare 
    cursor cur_dum is 
     select name,class,enroll_id from table_student; 
    rec_dum cur_dum%rowtype; 
begin 
    open cur_dum; 
    loop 
     fetch cur_dum into rec_dum; 
     exit when cur_dum%notfound; 
     update table_log 
     set statement = rec_dum.name || '-'||'-'||to_char(rec_dum.enroll_id) 
     where roll_id = rec_dum.enroll_id; 
    end loop; 
    close cur_dum; 
end; 

Hinweis: Ein Vorteil dieser expliziten Cursor-Notation ist, dass wir eine Variable zur Projektion der Abfrage des Cursors eingegeben definieren können (rec_dum oben).

Dies ist die gleiche Logik implizite Cursor-Notation:

declare 
    cursor cur_dum is 

    rec_dum cur_dum%rowtype; 
begin 
    for rec_dum in (select name,class,enroll_id from table_student) 
    loop 
     update table_log 
     set statement = rec_dum.name || '-'||'-'||to_char(rec_dum.enroll_id) 
     where roll_id = rec_dum.enroll_id; 
    end loop; 
end; 

„Hat die Masse sammeln hat, etwas zu tun, um die Nutzung der For-Schleife zu zwingen?“

BULK COLLECT ist die Syntax, die uns eine verschachtelte Tabelle Variable mit einem Satz von Datensätzen zu bevölkern können und so die Massenverarbeitung tun anstelle der Zeile-für-Zeile-Verarbeitung des oben dargestellten Grund FETCH; Mit dem Snippet, das Sie angeben, wird eine Teilmenge von 1000 Datensätzen gleichzeitig abgerufen, was beim Umgang mit großen Datenmengen erforderlich ist, da Variablen privaten (Sitzungs-) Speicher statt globalen (gemeinsamen Speicher) belegen.Der von Ihnen angegebene Code ist sehr schlecht, nicht zuletzt, weil auf die Anweisung FETCH ... BULK COLLECT INTO kein Test folgt, ob der FETCH irgendwelche Werte zurückgegeben hat. Da es keinen Test gibt, schlägt der nachfolgende Code zur Laufzeit fehl.

"Hat die Nutzung der for-Schleife in der Cursor-Schleife den Code schlecht machen?"

Nein, nicht automatisch. Zum Beispiel, wenn die Massenverarbeitung tun können wir oft so etwas tun:

<<batch_loop>> 
loop 
    fetch dum_cur bulk collect into dum_recs limit 1000; 
    exit when dum_recs.count() = 0; 
    <<row_loop>> 
    for idx in dum_recs.first()..dum_recs.last() 
    loop 
     do_something(dum_recs(idx)); 
    end loop row_loop; 
end loop batch_loop; 

Allerdings sollten wir misstrauisch verschachtelten CURSOR FOR-Schleife sein. Nested Loops sind in 3GL-Programme wie Java gemeinsam:

for (int i = 1; i <= 5; i++) { 
    for (int j = 1; j <= 10; j++) { 

So Entwickler vertraut mit diesem Stil oft Kodierung für verschachtelte Schleifen erreichen, wenn auf PL/SQL zu bewegen. Aber SQL ist ein Set-basiertes Paradigma. Es gibt normalerweise bessere Möglichkeiten, diese Logik zu implementieren, wie zum Beispiel ein JOIN: mache die beiden Cursor zu einem.

+0

Gibt es einen Grund, warum die for-Schleife verwendet wurde? –

+0

Macht die Verwendung von for-Schleife innerhalb der Cursor-Schleife den Code schlecht? Welcher Zweck könnte geeignet sein, zwei solche Schleifen zu verwenden? –