Renvoyer une table entièrement dynamique à partir d'une fonction Oracle


8

Je voudrais écrire une fonction avec deux INparamètres où le premier est un varcharet le second une liste de varchars. Sur la base de ceux-ci, je veux retourner un tableau avec différents montants de colonnes et noms de type varchar.

Pour autant que je l'ai vu, je dois toujours créer un objet / enregistrement et un type de table. Cela signifie que mon idée ne fonctionnera pas? L'objectif sous-jacent est de transmettre une sortie de commande système à un appelé en tant que table.

Edit: plus sur la tâche. Je veux émettre une commande OS, consommer la sortie et la renvoyer sous forme de tableau. La sortie de la commande OS va être des données au format CSV. Au moment de l'exécution, je ne connais pas la quantité de lignes à renvoyer mais seulement la quantité de colonnes qui est passée comme deuxième argument. Je pensais à utiliser Java avec une dynamique STRUCTet à les ARRAYcontenir. Bien que je préfère l'ancienne approche.

Ça devrait ressembler à ça:

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

Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White 9

Réponses:


1

Il est possible, bien que très compliqué, d'écrire une fonction de table en pipeline qui renvoie une structure variable . Votre fonction de table de pipeline pourrait prendre les deux arguments et utiliser l'interface Oracle Data Cartridge et la magie du type AnyDataSet pour renvoyer une structure dynamique au moment de l'exécution. Vous pouvez ensuite l'utiliser dans les instructions SQL suivantes comme s'il s'agissait d'une table, c'est-à-dire

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

Quelques références supplémentaires qui discutent du même exemple d'implémentation


0

Je pense que votre meilleure approche est d'abandonner la tentative de renvoyer une table dynamique (bien que je suppose que vous pourriez créer une table temporaire et lui renvoyer un refcurseur, mais je ne suis pas sûr ici).

Mon approche préférée ici serait de générer des résultats dans un format plus flexible, quelque chose comme un document XML ou similaire et de le renvoyer. Cela vous donne la flexibilité dont vous avez besoin sans avoir à déterminer les colonnes après l'analyse des fonctions.


Salut Chris, merci pour la réponse. J'ai déjà abandonné la table dynamique car elle n'est tout simplement pas possible. XML est trop verbeux mais une bonne idée. Mon principal problème est que j'aurais besoin d'appeler une fonction Java statique pour interroger un index lucene. Cela signifierait que je dois ouvrir et fermer l'index à chaque fois. C'est très inefficace. J'ai eu recours à un service REST avec sortie JSON et XML.
Michael-O

0

vous pouvez créer une vue tmp et remplacer la vue dynamiquement.

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;

résultats d'exécution:

entrez la description de l'image ici


-1

Une solution serait de créer une table externe basée sur la sortie Lucene. Vous pouvez facilement modifier la définition de table externe (et la pointer vers plusieurs fichiers).

Vous aurez donc:

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

Ça va marcher! La définition du fichier est connue et nous pouvons créer de façon dynamique une table externe.
Ohadi
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.