2012-04-25 24 views
8

Mam tabelę o nazwie Table1. Ma wiele kolumn, jedną z nich jest Kolumna1. Nie znam innych kolumn, czasami nawet się zmieniają. Istnieje typowy typ kursora ref, który zwraca Table1% rowtype, o nazwie cur_Table1. Mam procedurę składowaną o nazwie SP1, która ma parametr out typu cur_Table1. Nazywam tę procedurę składowaną SP1 z innej bazy danych, która widzi tylko tę procedurę składowaną, ale nie samą tabelę lub typ. Jak wybrać tylko kolumnę 1 ze zwróconego kursora? Wiem, że mogę pobrać rekord lub wiele zmiennych, ponieważ kursor ma kolumny, ale znam tylko jedną kolumnę, więc nie mogę zadeklarować kompletnego rekordu lub poprawnej liczby zmiennych.Oracle - wybierz konkretną kolumnę z kursora ref.

+0

Proszę wyjaśnić, w jaki sposób można wywołać procedurę w innej bazie danych (lub dowolnej bazie danych), bez możliwości zobaczenia typów argumentów. –

+0

Zrobiłem "wykonanie grantu na SP dla innego", ale nie przyznałem niczego innego, nie na stole lub pakiecie typów. I działa. – fejesjoco

+0

Aha, i po stronie wzywającej, oczywiście wstawiam parametr wyjściowy SP do sys_refcursor. – fejesjoco

Odpowiedz

6

Możesz to zrobić z DBMS_SQL, ale nie jest ładna.

danych tabeli i próbki (COLUMN1 ma numery 1 - 10):

create or replace package test_pkg is 
    type cur_Table1 is ref cursor return table1%rowtype; 
    procedure sp1(p_cursor in out cur_table1); 
end; 
/

create or replace package body test_pkg is 
    procedure sp1(p_cursor in out cur_table1) is 
    begin 
     open p_cursor for select column1, column2, column3, column4 from table1; 
    end; 
end; 
/

:

create table table1(column1 number, column2 date, column3 varchar2(1000), column4 clob); 

insert into table1 
select level, sysdate, level, level from dual connect by level <= 10; 
commit; 

pakiet z procedurą, która otwiera ref kursora i dokonuje wyboru wszystko Blok PL/SQL, który odczytuje dane COLUMN1 z kursora ref:

--Basic steps are: call procedure, convert cursor, describe and find columns, 
--then fetch rows and retrieve column values. 
-- 
--Each possible data type for COLUMN1 needs to be added here. 
--Currently only NUMBER is supported. 
declare 
    v_cursor sys_refcursor; 
    v_cursor_number number; 

    v_columns number; 
    v_desc_tab dbms_sql.desc_tab; 
    v_position number; 
    v_typecode number; 
    v_number_value number; 
begin 
    --Call procedure to open cursor 
    test_pkg.sp1(v_cursor); 
    --Convert cursor to DBMS_SQL cursor 
    v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor); 
    --Get information on the columns 
    dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab); 

    --Loop through all the columns, find COLUMN1 position and type 
    for i in 1 .. v_desc_tab.count loop 
     if v_desc_tab(i).col_name = 'COLUMN1' then 
      v_position := i; 
      v_typecode := v_desc_tab(i).col_type; 

      --Pick COLUMN1 to be selected. 
      if v_typecode = dbms_types.typecode_number then 
       dbms_sql.define_column(v_cursor_number, i, v_number_value); 
      --...repeat for every possible type. 
      end if; 
     end if; 
    end loop; 

    --Fetch all the rows, then get the relevant column value and print it 
    while dbms_sql.fetch_rows(v_cursor_number) > 0 loop 
     if v_typecode = dbms_types.typecode_number then 
      dbms_sql.column_value(v_cursor_number, v_position, v_number_value); 
      dbms_output.put_line('Value: '||v_number_value); 
     --...repeat for every possible type 
     end if; 
    end loop; 
end; 
/
+7

Wow ... i pomyślałem, że to będzie banalne jak "wybierz kolumnę 1 z kursora". – fejesjoco

1

Nie wiem, czy to opcja, czy nie, ale czy lepszym rozwiązaniem nie byłoby stworzenie funkcji zwracającej określoną wartość, której szukasz? Pozwala to uniknąć nadwyżki wysyłania dodatkowych danych. Alternatywnie możesz zdefiniować kursor z zestawem znanych pól, o których obie strony wiedzą.

+0

Nie mam kontroli nad bazą danych SP, po prostu muszę ją wywołać z innego miejsca jako klienta zewnętrznego. – fejesjoco

3

Biorąc pod uwagę pierwotne pytanie, odpowiedź Jonearlesa jest nadal poprawna, więc zostawię to zaznaczone jako takie, ale skończyło się na zrobieniu czegoś zupełnie innego i znacznie lepszego.

Problem polegał na tym, że nie mam kontroli nad bazą danych SP1, po prostu muszę ją wywołać z innego miejsca jako klienta zewnętrznego. Teraz udało mi się uzyskać pozwolenie na zobaczenie nie tylko SP, ale także rodzaju kursora. I nadal nie widzę tabeli, ale teraz jest znacznie czystsze rozwiązanie:

W drugiej bazie Zostałem zapewniony dostęp, aby zobaczyć ten typ now:

type cur_Table1 is ref cursor return Table1%rowtype; 

Więc w mojej bazy danych można zrobić teraz:

mycursor OtherDB.cur_Table1; 
myrecord mycursor%rowtype; 
... 
OtherDB.SP1(mycursor); 
fetch mycursor into myrecord; 
dbms_output.put_line(myrecord.Column1); 

Zobacz, nadal nie potrzebuję dostępu do stołu, widzę tylko kursor. Kluczem jest to, że magiczne% rowtype działa również dla kursorów, a nie tylko tabel. Nie działa na sys_refcursor, ale działa na silnie typizowanym. Biorąc pod uwagę ten kod, nie muszę przejmować się, jeśli cokolwiek zmieni się po drugiej stronie, nie muszę w ogóle definiować wszystkich kolumn ani rekordów, właśnie określam jedną kolumnę, która mnie interesuje.

Bardzo podoba mi się to podejście OOP dotyczące Oracle.

Powiązane problemy