“无法在查询中执行 DML 操作”的解决方案?

Posted

技术标签:

【中文标题】“无法在查询中执行 DML 操作”的解决方案?【英文标题】:Solution to "cannot perform a DML operation inside a query"? 【发布时间】:2012-02-02 11:51:51 【问题描述】:

我正在使用数据分析工具,我的要求是接受用户的值,将其作为参数传递并将其存储在表中。非常直截了当,所以我坐下来写这篇文章

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

我使用以下语句在 SQL Developer 中执行了此操作

begin
complex('SomeValue');  
end;

它工作正常,值被插入到表中。但是,数据分析工具不支持上述语句,所以我求助于使用函数。下面是函数的代码,它可以编译。

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

我再次尝试在 SQL Developer 中执行它,但是在执行以下代码时,我得到 cannot perform a DML operation inside a query

select supercomplex('somevalue') from dual;

我的问题是 - 我需要一个可以在 SQL Developer 中运行上述函数的语句,或者 - 一个可以执行我正在寻找的功能,可以通过 select 语句执行。 - 如果无法按照我的要求做,我想要一个理由,以便我可以通知我的经理,因为我对 PL/SQL 很陌生(比如一周大?)所以我不了解规则和语法。

附:我多么希望这是 C++ 甚至 Java :(

编辑

我需要在 SQL Developer 上运行该函数,因为在 DMine(这是该工具)中运行它之前,以测试它是否有效。 SQL 中的任何无效内容在 Dmine 中也是无效的,但反之则不然。

感谢您的帮助,我了解情况以及为什么它是非法/不推荐的

【问题讨论】:

您得到的错误不是 SQL Developer 特定的,它是一个 Oracle 错误,而且非常简单:您不能在查询中对数据库进行修改。大概这是由于隔离级别,以保持 ACID 合规性;否则你可以同时修改你正在查询的表,所有的地狱都会崩溃! 您能解释一下为什么需要在 SQL Developer 中调用函数吗?为什么这很重要? 数据分析工具不支持?什么工具?如果您可以在此工具中运行 SQL,您应该能够运行脚本(您最初显示的匿名块)。 【参考方案1】:

您可以使用指令pragma autonomous_transaction。这会将函数运行到一个独立的事务中,该事务将能够在不引发 ORA-14551 的情况下执行 DML。

请注意,由于autonomous transaction 是独立的,因此 DML 的结果将在父事务范围之外提交。在大多数情况下,这不是可接受的解决方法。

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 has a nice explanation 首先说明为什么会出现错误。这是不安全的,因为它可能取决于处理行的顺序。此外,Oracle 不保证该函数每行至少执行一次,最多执行一次。

【讨论】:

【参考方案2】:

只需声明一个变量来接受返回值,例如:

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

选择不起作用,因为该函数正在执行插入,如果它所做的只是返回一个值,那么它会起作用。

【讨论】:

您忘记包含用于保存返回值的变量。 完美!谢谢 如果您从高级编程语言(C#/Java)执行此查询,您如何访问我的程序中的retvar【参考方案3】:

只需在虚拟if ... end if; 语句中执行函数即可忽略返回值:

exec if supercomplex('somevalue') then null; end if;

或者作为put_line过程的参数执行,输出返回值:

exec dbms_ouput ('result of supercomplex='||supercomplex('somevalue'));

result of supercomplex=done

【讨论】:

以上是关于“无法在查询中执行 DML 操作”的解决方案?的主要内容,如果未能解决你的问题,请参考以下文章

VS2005中的生成解决方案, 清理解决方案是啥意思?

什么是 沙盒解决方案

「解决方案架构」解决方案架构概述

https页面混合http解决方案

Visual Studio 中构建解决方案、重建解决方案和清理解决方案之间的区别?

如何解决网络监听?您有几中解决方案?