-2

我有一个创建新临时表的 PL/SQL 函数。为了创建我使用的表execute immediate。当我在 oracle sql developer 中运行我的函数时,一切正常;该函数创建没有错误的临时表。但是当你使用 SQL 时:

Select function_name from table_name

我得到一个例外:

ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML
ORA-06512: at "SYSTEM.GET_USERS", line 10
14552. 00000 -  "cannot perform a DDL, commit or rollback inside a query or DML "
*Cause:    DDL operations like creation tables, views etc. and transaction
       control statements such as commit/rollback cannot be performed
       inside a query or a DML statement.

更新

抱歉,从平板电脑写入,文本格式有问题。我的功能:

CREATE OR REPLACE FUNCTION GET_USERS 
(
    USERID IN VARCHAR2
)
RETURN VARCHAR2 
AS
    request VARCHAR2(520) := 'CREATE GLOBAL TEMPORARY TABLE ';
BEGIN
    request := request || 'temp_table_' || userid || 
            '(user_name varchar2(50), user_id varchar2(20), is_administrator varchar2(5)') ||
            ' ON COMMIT PRESERVE ROWS';
    EXECUTE IMMEDIATE (request);
    RETURN 'true';
END GET_USERS;
4

2 回答 2

2

错误是明确的:

ORA-14552: 无法在查询或 DML 中执行 DDL、提交或回滚

在 Oracle 中,您不能在查询中提交。一个可能的解释是它没有任何意义,因为 Oracle 中的查询是原子的(要么完全成功,要么不做任何更改),如果您在 DML 中间提交,这将无法工作。对于选择查询,必须从单个逻辑时间点返回所有行,如果您在选择中间提交,您将得到不一致的结果。

由于 Oracle 中的 DDL 发出隐式提交,因此您不能在查询中进行 DDL。

不过,这在您的情况下应该不是问题:类似 SQL 服务器的临时表不等同于 Oracle中的GLOBALLY临时表。Oracle 中的临时表总是以 为前缀是有原因的GLOBALLY:尽管临时表中的数据对每个会话都是私有的,但它们对所有会话都是可见的。

在 Oracle 中,创建临时表是一项相对昂贵的操作,您不应该创建单独的临时表:所有执行相同工作的会话都应该使用相同的公共结构。而不是创建多个临时表,在 Oracle 中,您应该创建一次表并在所有过程中重用它。如果您以后需要它,为什么要放弃它?

在任何情况下,如果您决定执行多个依赖于 SELECT 的 DDL,您可以在 PLSQL 块而不是 SELECT 查询中执行它:

DECLARE
   l VARCHAR2(100);
BEGIN
   FOR cc IN (SELECT col FROM tab) LOOP
      l := create_temp_table(cc.col);
   END LOOP;
END;
于 2012-10-24T16:17:27.900 回答
0

我在 Oracle 10g XE 上测试了以下解决方案,它对我有用。

创建函数:

CREATE OR REPLACE FUNCTION GET_USERS 
(
    USERID IN VARCHAR2
)
RETURN VARCHAR2 
AS
    request VARCHAR2(255) := 'CREATE GLOBAL TEMPORARY TABLE ';
BEGIN
    request := request || 'temp_table_' || userid || 
            '(user_name varchar2(50), user_id varchar2(20), is_administrator varchar2(5))' ||
            ' ON COMMIT PRESERVE ROWS';
    EXECUTE IMMEDIATE request;
    RETURN 'true';
END GET_USERS;

运行功能:

SET SERVEROUTPUT ON
DECLARE
 RESULT  VARCHAR(255);
BEGIN
   RESULT:=gET_USERS('ADMIN3');
   dbms_output.put_line(result);
END;

并从临时表中选择:

SELECT * FROM temp_table_admin3;
于 2012-10-24T19:14:43.673 回答