2012-04-25 23 views
8

Tengo una tabla llamada Tabla1. Tiene muchas columnas, una de ellas es Column1. No conozco las otras columnas, incluso pueden cambiar algunas veces. Hay un tipo de cursor de refferencia fuertemente tipado que devuelve Table1% rowtype, llamado cur_Table1. Tengo un procedimiento almacenado llamado SP1 que tiene un parámetro out de tipo cur_Table1. Estoy llamando a este procedimiento almacenado SP1 desde otra base de datos que solo ve este procedimiento almacenado, pero no la tabla o el tipo en sí. ¿Cómo selecciono solo Column1 del cursor devuelto? Sé que puedo buscar en un registro o tantas variables como el cursor tiene columnas, pero solo sé de la existencia de una columna, por lo que no puedo declarar el registro completo o el número correcto de variables.Oracle: seleccione una columna específica de un cursor de referencia

+0

Explique cómo propone llamar a un procedimiento en otra base de datos (o cualquier base de datos, para el caso) sin poder ver los tipos de los argumentos. –

+0

Hice una "concesión de ejecución de SP a otro", pero no otorgué ninguna otra cosa, ni en la tabla ni en el paquete de tipos. Y funciona. – fejesjoco

+0

Ah, y por el lado de las llamadas, pongo el parámetro out de SP en un sys_refcursor, por supuesto. – fejesjoco

Respuesta

6

Puede hacerlo con DBMS_SQL, pero no es bonito.

de mesa y de la muestra de datos (COLUMN1 tiene los números 1 - 10):

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; 

paquete con un procedimiento que se abre un cursor ref y selecciona todo:

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; 
/

Bloque PL/SQL que lee datos COLUMN1 del cursor de 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

Guau ... y pensé que sería algo trivial como "seleccionar columna1 del cursor". – fejesjoco

1

No sé si es una opción o no, pero ¿no sería una mejor solución crear una función que devuelva el valor específico que está buscando? Eso evita la sobrecarga de enviar los datos adicionales. Alternativamente, podría definir un cursor con un conjunto de campos conocidos en el que las dos partes conocen.

+0

No tengo control sobre la base de datos de SP, solo tengo que llamarlo desde otro lugar como cliente de un tercero. – fejesjoco

3

Dada la pregunta original, la respuesta de jonearles sigue siendo la correcta, así que lo dejo marcado como tal, pero terminé haciendo algo completamente diferente y mucho mejor.

El problema era/es que no tengo control sobre la base de datos del SP1, solo tengo que llamarlo desde otro lugar como un cliente externo. Ahora logré obtener permiso para ver no solo SP, sino también el tipo de cursor. Todavía no veo la mesa, pero ahora hay una solución mucho más limpio:

En la otra base de datos que se ha concedido acceso para ver este tipo ahora:

type cur_Table1 is ref cursor return Table1%rowtype; 

Así que en mi base de datos que pueda hacer esto ahora:

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

Ver, todavía no necesito ningún acceso a la tabla, solo veo el cursor. La clave es que el% de tipo de fila mágico también funciona para los cursores, no solo para las tablas. No funciona en sys_refcursor, pero lo hace en uno fuertemente tipado. Dado este código, no me tiene que importar si algo cambia en el otro lado, no tengo que definir todas las columnas o registros, solo especifico la columna que me interesa.

Me encanta esta actitud de OOP sobre Oracle.

Cuestiones relacionadas