Oracle 立即执行 DDL 和嵌套表
Posted
技术标签:
【中文标题】Oracle 立即执行 DDL 和嵌套表【英文标题】:Oracle Execute Immediate with DDL and Nested table 【发布时间】:2014-03-12 19:00:01 【问题描述】:我在尝试使用包含CREATE TABLE
语句和用户定义的表类型的Execute Immediate
语句时遇到问题。我在 Oracle 11g 上收到错误 ORA-22905
。
有什么办法可以解决这个问题吗?
CREATE TYPE MY_TABLE_TYPE AS TABLE OF VARCHAR2(30);
/
DECLARE
MT MY_TABLE_TYPE;
BEGIN
SELECT * BULK COLLECT INTO MT FROM DUAL;
-- Two steps
EXECUTE IMMEDIATE 'CREATE TABLE MY_TABLE1 (A VARCHAR2(30))';
EXECUTE IMMEDIATE 'INSERT INTO MY_TABLE1 SELECT * FROM TABLE(:T)' USING MT; -- OK
-- One step
EXECUTE IMMEDIATE 'CREATE TABLE MY_TABLE2 AS SELECT * FROM TABLE(:T)' USING MT; -- ERROR ORA-22905
END;
SELECT * FROM TABLE(:T)
的真实代码是动态的(主表名是临时的)并且速度很慢。这就是为什么我尽量避免分两步创建表(如MY_TABLE1
所做的那样)。同样通过两个步骤,我不能使用SELECT *
,但我必须指定所有列(可变数量和超过 100 列)。
【问题讨论】:
您是否有理由不能在原始表上使用视图而不是创建和填充临时表? 此代码在作业中执行,最多可能需要 2 小时才能完成,最多可提取 500.000 条记录。结果可以立即多次查看(那些“临时”表的用户会话生命周期)。 所以通过将数据移动到各处来构建这张表需要两个小时。在没有所有存储分配等的情况下执行查询需要多长时间? 执行 SELECT 可能需要两个小时,因为记录是从超过 3 亿条记录的表中提取的。平均执行时间在 2 到 10 分钟之间,有时搜索值较大时需要长达 2 小时。创建表和插入数据是一个相对较快的过程(几秒钟的问题)。 同样使用视图我无法绑定变量,这会产生错误:EXECUTE IMMEDIATE 'CREATE VIEW MY_TABLE2 AS SELECT * FROM TABLE(:T)' USING MT; 【参考方案1】:可能有一种方法可以完全避免这个问题。跳过批量收集并使用简单的CREATE TABLE MY_TABLE AS SELECT * FROM DUAL;
这可能是对收集数据的真实逻辑的过度简化。但几乎总有一种方法可以绕过批量收集并将数据直接存储在一个对象中,只需要 SQL。
如果确实需要 PL/SQL 解决方案,则可以通过创建对象类型并基于该类型创建表来避免错误 ORA-22905: cannot access rows from a non-nested table item
。这可能无法解决性能问题,但至少避免了重新指定表 DDL 中所有列的需要。
CREATE TYPE MY_TABLE_OBJECT IS OBJECT
(
A VARCHAR2(30)
);
CREATE TYPE MY_TABLE_TYPE2 AS TABLE OF VARCHAR2(30);
DECLARE
MT MY_TABLE_TYPE2;
BEGIN
SELECT * BULK COLLECT INTO MT FROM DUAL;
EXECUTE IMMEDIATE 'CREATE TABLE MY_TABLE2 OF MY_TABLE_OBJECT';
EXECUTE IMMEDIATE 'INSERT INTO MY_TABLE2 SELECT * FROM TABLE(:T)' USING MT;
END;
/
【讨论】:
您仍在使用两个步骤(如在我的第一个有效示例中)。在实际代码中,MY_TABLE1/2 具有超过 100 列的可变数量,并且 SELECT 是大表和 TABLE(:T) 之间的连接。性能不是这个问题的问题。 是的,这个版本仍然使用两个步骤,但第一步现在更简单,不需要指定所有列。我认为没有办法一步到位。以上是关于Oracle 立即执行 DDL 和嵌套表的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate 和 Oracle VARRAYS/嵌套表