Gibt eine vollständig dynamische Tabelle von einer Oracle-Funktion zurück

8

Ich möchte eine Funktion mit zwei INParametern schreiben, wobei der erste eine varcharund der zweite eine Liste von ist varchars. Basierend auf diesen möchte ich eine Tabelle mit unterschiedlichen Spaltenmengen und Typnamen zurückgeben varchar.

Soweit ich gesehen habe, muss ich immer ein Objekt / einen Datensatz und einen Tabellentyp davon erstellen. Das bedeutet, dass meine Idee nicht funktioniert? Das zugrunde liegende Ziel besteht darin, eine Systembefehlsausgabe als Tabelle an einen Angerufenen zurückzugeben.

Bearbeiten: mehr zur Aufgabe. Ich möchte einen Betriebssystembefehl ausgeben, die Ausgabe verbrauchen und als Tabelle zurückgeben. Die Ausgabe des OS-Befehls sind CSV-formatierte Daten. Zum Zeitpunkt der Ausführung kenne ich nicht die Anzahl der zurückzugebenden Zeilen, sondern nur die Anzahl der Spalten, die als zweites Argument übergeben werden. Ich dachte darüber nach, Java mit einer Dynamik zu verwenden STRUCTund sie zu ARRAYenthalten. Obwohl ich den früheren Ansatz vorziehen würde.

Es sollte so aussehen:

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
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Paul White 9

Antworten:

1

Es ist möglich, obwohl ziemlich kompliziert, eine Pipeline-Tabellenfunktion zu schreiben , die eine variable Struktur zurückgibt . Ihre Pipeline-Tabellenfunktion könnte die beiden Argumente verwenden und die Oracle Data Cartridge-Schnittstelle und die Magie des AnyDataSet-Typs verwenden, um zur Laufzeit eine dynamische Struktur zurückzugeben. Sie können dies dann in nachfolgenden SQL-Anweisungen verwenden, als wäre es eine Tabelle, d. H.

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

Ein paar weitere Referenzen, die dieselbe Beispielimplementierung behandeln

Justin Cave
quelle
0

Ich denke, Ihr bester Ansatz besteht darin, den Versuch, eine dynamische Tabelle zurückzusenden, abzubrechen (obwohl Sie möglicherweise eine temporäre Tabelle erstellen und einen Refcursor darauf zurückgeben können, aber ich bin mir hier nicht sicher).

Mein bevorzugter Ansatz hier wäre es, Ergebnisse in einem flexibleren Format, etwa einem XML-Dokument oder ähnlichem, zu generieren und zurückzugeben. Dies gibt Ihnen die Flexibilität, die Sie benötigen, ohne dass die Spalten nach dem Funktionsscan festgelegt werden müssen.

Chris Travers
quelle
Hallo Chris, danke für die Antwort. Ich habe die dynamische Tabelle bereits aufgegeben, weil es einfach nicht möglich ist. XML ist zu ausführlich, aber eine gute Idee. Mein Hauptproblem ist, dass ich eine statische Java-Funktion aufrufen müsste, um einen Lucene-Index abzufragen. Dies würde bedeuten, dass ich den Index jedes Mal öffnen und schließen muss. Das ist sehr ineffizient. Ich habe auf einen REST-Service mit JSON- und XML-Ausgabe zurückgegriffen.
Michael-O
0

Sie können eine tmp-Ansicht erstellen und die Ansicht dynamisch ersetzen.

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;

Ausführungsergebnisse:

Geben Sie hier die Bildbeschreibung ein

Rayika Lao
quelle
-1

Eine Lösung wäre, eine externe Tabelle basierend auf der Lucene-Ausgabe zu erstellen. Sie können die externe Tabellendefinition leicht ändern (und auf mehrere Dateien verweisen).

So haben Sie:

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
quelle
Es wird klappen! Die Definition der Datei ist bekannt und wir können automatisch eine externe Tabelle erstellen.
Ohadi