2009-11-13 5 views
7

To jest jedna z tych pytań "tam musi być lepsza droga". Pozwól mi skonfigurować problem, a następnie dam ci moje zhakowane rozwiązanie i być może zaproponujesz lepsze rozwiązanie. Dzięki!Resetowanie asocjacyjnej tablicy w PL/SQL?

Weźmy ten mały smakołyk PL/SQL

DECLARE 
TYPE foo_record IS RECORD (foo%type, bar%type); 
TYPE foo_records IS TABLE OF foo_record INDEX BY PLS_INTEGER; 
arr_foos foo_records; 

CURSOR monkeys is SELECT primates FROM zoo; 
row_monkey monkeys%rowtype; 
BEGIN 
FOR row_monkey IN monkeys loop 
    /* 
    at this point in each iteration I need to have the associative array 
    arr_foos in its original state. if this were java, I'd declare it 
    right here and its scope would be limited to this iteration. However, 
    this is not java, so the scope of the array is effectively global and 
    I can't have one iteration's data meddle with the next. 
    */ 
    null; 
END LOOP; 
END; 

Czy to ma sens? Zasadniczo muszę to zresetować. Jeśli był to numer zaczynający się od zera, mógłbym powiedzieć number: = 0; na szczycie każdej iteracji i zrób to. Ale to nie jest liczba, to typ, który mogę po prostu zresetować czystym: = 0.

W każdym razie, na mój Hack:

DECLARE 
TYPE foo_record IS RECORD (foo%type, bar%type); 
TYPE foo_records IS TABLE OF foo_record INDEX BY PLS_INTEGER; 
arr_foos foo_records; 
arr_foos_reset foo_records; 

CURSOR monkeys is SELECT primates FROM zoo; 
row_monkey monkeys%rowtype; 
BEGIN 
FOR row_monkey IN monkeys loop 
    arr_foos := arr_foos_reset; 
    null; 
END LOOP; 
END; 

Pomyślałem, że jeśli uda mi się zachować element tego samego typu w oryginalnym stanie, to mogę tylko ustawić zmienną roboczą z powrotem do dowolnej wartości jest z oryginału. I, o dziwo, działa (chyba.) Ale musi być lepszy sposób. Czy ktoś może pomóc?

T'anks!

+1

Minor nitpick: nie trzeba zadeklarować 'row_monkey małp% rowtype;'. Kursor pętli podobnej do tej wykonuje deklarację i ogranicza się do treści pętli. W tym kodzie zmienna jest zadeklarowana dwa razy, a wersja wewnętrzna cienia zewnętrzną. Nie stanowi to jednak problemu - pomyślałem, że dodam to dla każdego, kto czyta. – AdamRossWalker

Odpowiedz

18

Najłatwiej:

arr_foos.Delete(); 

Inny sposób to zadeklarować zmienną wewnątrz pętli FOR. W ten sposób zostanie on odtworzony dla każdego przejścia.

Jak to:

DECLARE 
TYPE foo_record IS RECORD (foo%type, bar%type); 
TYPE foo_records IS TABLE OF foo_record INDEX BY PLS_INTEGER;  

CURSOR monkeys is SELECT primates FROM zoo; 
row_monkey monkeys%rowtype; 
BEGIN 
FOR row_monkey IN monkeys loop 
    DECLARE 
    arr_foos foo_records; 
    BEGIN 
    null; 
    END; 
END LOOP; 
END; 
+2

Dzięki! Nie zdawałem sobie sprawy, że możesz powiedzieć DECLARE po BEGIN. (: – steve

+2

Można zagnieździć się dowolną liczbę razy, w ten sposób można również przechwytywać wyjątki w mniejszych blokach kodu (np. Try/catch w języku C# lub Java). Bardzo przydatna funkcja moim zdaniem – Majkel

1

Idziesz do odczytu danych z tabeli zoo w kolekcji? Potem jest lepszy sposób:

DECLARE 
    type foos_ts is table of zoo.foo%type index by pls_integer; 
    foos foos_t; 
BEGIN 
    select foo 
    bulk collect into foos 
    from zoo; 
    ... 
END; 

luzem zbierać automatycznie czyści kolekcję przed pobraniem i działa szybciej niż czytać wiersz po wierszu w pętli. Niestety nie działa z rekordami, więc będziesz potrzebował kilku tabel PL/SQL dla każdego pola.

można znaleźć dodatkowe informacje można znaleźć tutaj: Retrieving Query Results into Collections with the BULK COLLECT Clause

+0

dobra wskazówka, dzięki – steve