【发布时间】:2012-04-02 15:58:37
【问题描述】:
我编写了一个 Oracle 函数(用于 8i)来获取受 DML 语句影响的行,模拟来自 PostgreSQL 的 RETURNING * 的行为。典型的函数调用如下所示:
SELECT tablename_dml('UPDATE tablename SET foo = ''bar''') FROM dual;
该函数是为每个表自动创建的,并使用动态 SQL 执行作为参数传递的查询。此外,动态执行查询的语句也包含在 BEGIN .. END 块中:
EXECUTE IMMEDIATE 'BEGIN'||query||' RETURNING col1, col2 BULK COLLECT INTO :1, :2;END;' USING OUT col1_t, col2_t;
这种特殊构造背后的原因是,它似乎是从影响多行的 DML 语句中获取值的唯一方法。 col1_t 和 col2_t 都声明为与表列对应的类型的集合。
最后,解决问题。当传递的查询包含子选择时,函数的执行会产生语法错误。下面是一个简单的例子来说明这一点:
CREATE TABLE xy(id number, name varchar2(80));
CREATE OR REPLACE FUNCTION xy_fn(query VARCHAR2) RETURN NUMBER IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'BEGIN '||query||'; END;';
ROLLBACK;
RETURN 5;
END;
SELECT xy_fn('update xy set id = id + (SELECT min(id) FROM xy)') FROM DUAL;
最后一条语句产生以下错误:(那里提到的 SELECT 是 SELECT min(id))
ORA-06550:第 1 行,第 32 列:PLS-00103:遇到符号 “SELECT”当期望以下之一时:( - + mod not null 其他 avg count 当前存在 max min prior sql stddev sum 方差执行forall时间时间戳间隔日期
此问题发生在 8i (8.1.6) 上,但不是 10g。 如果 BEGIN .. END 块被删除 - 问题就消失了。 如果查询中的子选择被替换为其他内容,即常量,问题就会消失。
不幸的是,我坚持使用 8i 并删除 BEGIN .. END 不是一个选项(请参阅上面的解释)。
这里有特定的 Oracle 8i 限制吗?是否可以通过动态 SQL 来克服它?
【问题讨论】:
-
8i??延长支持已于 5 年前结束...
-
@Ben:你可以笑,但我仍在对 8i 数据库实例进行更改...
-
@JeffreyKemp,我没笑!我知道有时很难移动(我还有一些相互连接的 9i 盒子 - 但我们已经升级了它们)。如果真的应该使用受支持的版本……这比使用不受支持的版本更有意义。
-
@ben - 有问题的版本是 8.1.6,甚至不是 8i 的终端版本。所以无论如何都没有资格获得扩展支持。
-
我实际上正在将数据迁移到 PostgreSQL,但我仍然需要 8i 来保证转换的质量。