我无法说服为什么我不能在 Oracle函数中添加DML操作,特别是在游标循环中。我觉得Oracle不支持游标循环中的DML操作。
我该怎么办如果我需要在游标循环中插入表格?在其中创建新的商店程序或其他东西?
错误消息:无法在查询中执行DML操作
这是我的功能,
CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2)
RETURN VARCHAR2
IS
V_MESSAGE VARCHAR2(30);
CURSOR C_PERSON (V_ID VARCHAR2) IS
SELECT NAME_UPPER
FROM TBL_PERSON
WHERE NAME_UPPER = V_ID;
BEGIN
FOR C_PERSON_CURSOR IN C_PERSON(U_ID)
LOOP
INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER);
END LOOP;
RETURN V_MESSAGE;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
答案 0 :(得分:12)
你可以在PL / SQL函数中使用DML - 没问题。但是,该函数只能从PL / SQL调用,而不能从SQL调用 - 即它可以像这样调用:
declare
l_message varchar2(30);
begin
l_message := test_func('123');
end;
......但不是这样的:
select test_func(empno) from emp;
这会导致您发布的错误消息。
许多人(包括我)不喜欢具有这种“副作用”的功能,但这是最佳实践和标准问题,而不是技术问题。
答案 1 :(得分:11)
您可以在Oracle PL / SQL函数中执行DML操作,虽然这通常不是一个好习惯,但请从SQL 调用它。该函数必须用pragma AUTONOMOUS_TRANSACTION
标记,并且必须在退出函数之前提交或回滚事务(参见AUTONOMOUS_TRANSACTION Pragma)。
您应该知道,这种从SQL调用的函数可以大大降低您的查询性能。我建议您仅将用于审核目的。
以下是从您的函数开始的示例脚本:
CREATE TABLE TBL_PERSON (NAME_UPPER VARCHAR2(30)); CREATE TABLE TMP_PERSON (NAME VARCHAR2(30)); INSERT INTO TBL_PERSON (NAME_UPPER) VALUES ('KING'); CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; -- Needed to be called from SQL V_MESSAGE VARCHAR2(2000); CURSOR C_PERSON (V_ID VARCHAR2) IS SELECT NAME_UPPER FROM TBL_PERSON WHERE NAME_UPPER = V_ID; BEGIN FOR C_PERSON_CURSOR IN C_PERSON(U_ID) LOOP INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER); V_MESSAGE := SQL%ROWCOUNT || ' Person record successfully inserted into TMP_PERSON table'; END LOOP; COMMIT; -- The current autonomous transaction need to be commited -- before exiting the function. RETURN V_MESSAGE; EXCEPTION WHEN OTHERS THEN ROLLBACK; raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM); END; / PROMPT Call the TEST_FUNC function and insert a new record into TMP_PERSON table SELECT TEST_FUNC('KING') FROM DUAL; PROMPT Content of the TMP_PERSON table COL NAME FOR A30 SELECT * FROM TMP_PERSON;
运行上一个脚本时,我们得到以下输出:
Table created. Table created. 1 row created. Function created. Calling the TEST_FUNC function and insert a new record into TMP_PERSON table TEST_FUNC('KING') ------------------------------------------------------------ 1 Person record successfully inserted into TMP_PERSON table Content of the TMP_PERSON table NAME ------------------------------ KING