Devuelve una tabla completamente dinámica desde una función de Oracle

8

Me gustaría escribir una función con dos INparámetros donde el primero es ay varcharel segundo una lista de varchars. En base a estos, quiero devolver una tabla con cantidades variables de columna y nombres de tipo varchar.

Por lo que he visto, siempre tengo que crear un objeto / registro y un tipo de tabla. ¿Esto significa que mi idea no funcionará? El objetivo subyacente es pasar una salida del comando del sistema a un destinatario como una tabla.

Editar: más sobre la tarea. Quiero emitir un comando del sistema operativo, consumir el resultado y devolverlo como una tabla. El resultado del comando del sistema operativo será datos con formato CSV. En el momento de la ejecución, no sé la cantidad de filas que se devolverán, sino solo la cantidad de columnas que se pasa como el segundo argumento. Estaba pensando en usar Java con una dinámica STRUCTy ARRAYcontenerlos. Aunque preferiría el enfoque anterior.

Debe tener un aspecto como este:

create function(clob query, list of varchars cols) returns table
begin
  execute system command(query, cols);
  examine sysout from command;
  return tabular data from syscmd as table;
end
Michael-O
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White 9

Respuestas:

1

Es posible, aunque bastante complicado, escribir una función de tabla canalizada que devuelva una estructura variable . La función de la tabla de canalización podría tomar los dos argumentos y utilizar la interfaz de Oracle Data Cartridge y la magia del tipo AnyDataSet para devolver una estructura dinámica en tiempo de ejecución. Luego puede usar eso en las siguientes declaraciones SQL como si fuera una tabla, es decir

SELECT *
  FROM TABLE( your_pipelined_function( p_1, p_2 ));

Un par de referencias más que analizan la misma implementación de muestra

Justin Cave
fuente
0

Creo que su mejor enfoque es abandonar el intento de devolver una tabla dinámica (aunque supongo que podría crear una tabla temporal y devolverle un refcursor, pero no estoy seguro aquí).

Mi enfoque preferido aquí sería generar resultados en un formato más flexible, algo así como un documento XML o similar y devolverlo. Esto le brinda la flexibilidad que necesita sin tener que determinar las columnas después del escaneo de funciones.

Chris Travers
fuente
Hola Chris, gracias por la respuesta. Ya he abandonado la tabla dinámica porque simplemente no es posible. XML es demasiado detallado pero es una buena idea. Mi principal problema es que necesitaría llamar a una función Java estática para consultar un índice lucene. Esto significaría que necesito abrir y cerrar el índice cada vez. Esto es muy poco eficiente. He recurrido a un servicio REST con salida JSON y XML.
Michael-O
0

puede crear una vista tmp y reemplazar la vista dinámicamente.

create or replace view tmp_view as select 1 x from dual;
/
create or replace package pkg_input_sql is
  cursor my_cursor is select * from tmp_view;

  my_rec_type my_cursor%rowtype;
  type my_tab_type is table of my_cursor%rowtype;

  function get_cursor(p_sqlstr varchar2) return sys_refcursor;
  function get_table return my_tab_type
    pipelined;

end pkg_input_sql;
/
create or replace package body pkg_input_sql is

  function get_cursor(p_sqlstr varchar2) return sys_refcursor as
    my_cursor sys_refcursor;
  begin
    open my_cursor for p_sqlstr;
    return my_cursor;
  end get_cursor;

  function get_table return my_tab_type
    pipelined is
    my_tab    my_tab_type;
    i         pls_integer;
    my_cursor sys_refcursor;
  begin
    my_cursor := get_cursor('select * from tmp_view');
    fetch my_cursor bulk collect
      into my_tab;
    for i in 1 .. my_tab.count loop
      pipe row(my_tab(i));
    end loop;
  end;

begin
  null;
end pkg_input_sql;
/

create or replace procedure create_tmp_view(p_sqlstr varchar2) is
begin
  execute immediate 'create or replace view tmp_view as ' || p_sqlstr;
  dbms_utility.exec_ddl_statement('alter package pkg_get_sql compile package');
  dbms_session.reset_package; -- to avoid ora-04068
end create_tmp_view;

resultados de ejecución:

ingrese la descripción de la imagen aquí

Rayika Lao
fuente
-1

Una solución sería crear una tabla externa basada en la salida de Lucene. Puede modificar fácilmente la definición de tabla externa (y señalarla a varios archivos).

Entonces tendrás:

function l_query(clob query, list of varchars cols) returns table_name
begin 
execute system command(query, cols); 
#hopefully we know the output filename
create a new external table mapping the output;
end
Ohadi
fuente
¡Funcionará! La definición del archivo es conocida y podemos crear dinámicamente una tabla externa.
Ohadi