web-dev-qa-db-fra.com

Solution à "ne peut pas effectuer une opération DML dans une requête"?

J'utilise un outil d'analyse de données et l'exigence que j'avais était d'accepter une valeur de l'utilisateur, de la transmettre en tant que paramètre et de la stocker dans une table. Assez droit donc je me suis assis pour écrire ceci

create or replace
procedure complex(datainput in VARCHAR2)
is
begin
insert into dumtab values (datainput);
end complex;

J'ai exécuté ceci dans SQL Developer en utilisant l'instruction suivante

begin
complex('SomeValue');  
end;

Cela a bien fonctionné et la valeur a été insérée dans le tableau. Cependant, les instructions ci-dessus ne sont pas prises en charge dans l'outil d'analyse de données, j'ai donc eu recours à une fonction à la place. Ce qui suit est le code de la fonction, il compile.

create or replace
function supercomplex(datainput in VARCHAR2)
return varchar2
is
begin
insert into dumtab values (datainput);
return 'done';
end supercomplex;   

Encore une fois, j'ai essayé de l'exécuter dans SQL Developer, mais j'ai obtenu ne peut pas effectuer d'opération DML dans une requête lors de l'exécution du code suivant

select supercomplex('somevalue') from dual;

Ma question est - J'ai besoin d'une instruction qui peut exécuter la fonction mentionnée dans SQL Developer ou - Une fonction qui peut effectuer ce que je recherche et qui peut être exécutée par l'instruction select. - S'il n'est pas possible de faire ce que je demande, je voudrais une raison pour que je puisse informer mon manager car je suis très nouveau (comme une semaine?) En PL/SQL donc je ne suis pas au courant des règles et syntaxes.

P.S. Comment je souhaite que ce soit C++ ou même Java :(

MODIFIER

J'ai besoin d'exécuter la fonction sur SQL Developer car avant de l'exécuter dans DMine (qui est l'outil) afin de tester si elle est valide ou non. Tout ce qui n'est pas valide dans SQL l'est également dans DMine, mais pas l'inverse.

Merci pour l'aide, j'ai compris la situation et pourquoi elle est illégale/non recommandée

25
Joshua1729

Vous pouvez utiliser la directive pragma autonomous_transaction. Cela exécutera la fonction dans une transaction indépendante qui pourra exécuter DML sans augmenter l'ORA-14551.

Sachez que puisque la transaction autonome est indépendante, les résultats du DML seront validés en dehors de la portée de la transaction parente. Dans la plupart des cas, ce ne serait pas une solution de contournement acceptable.

SQL> CREATE OR REPLACE FUNCTION supercomplex(datainput IN VARCHAR2)
  2     RETURN VARCHAR2 IS
  3     PRAGMA AUTONOMOUS_TRANSACTION;
  4  BEGIN
  5     INSERT INTO dumtab VALUES (datainput);
  6     COMMIT;
  7     RETURN 'done';
  8  END supercomplex;
  9  /

Function created

SQL> SELECT supercomplex('somevalue') FROM dual;

SUPERCOMPLEX('SOMEVALUE')
--------------------------------------------------------------------------------
done

SQL> select * from dumtab;

A
--------------------------------------------------------------------------------
somevalue

Tom Kyte a une belle explication sur la raison pour laquelle l'erreur est déclenchée en premier lieu. Ce n'est pas sûr car cela peut dépendre de l'ordre dans lequel les lignes sont traitées. De plus, Oracle ne garantit pas que la fonction sera exécutée au moins une fois et au plus une fois par ligne.

43
Vincent Malgrat

Déclarez simplement une variable pour accepter la valeur de retour, par exemple:

declare
    retvar varchar2(4);
begin
    retvar := supercomplex('somevalue');
end;

La sélection ne fonctionne pas car la fonction effectue une insertion, si tout ce qu'elle a fait était de renvoyer une valeur, cela fonctionnerait.

12
John Doyle