立即执行结果到表类型

Posted

技术标签:

【中文标题】立即执行结果到表类型【英文标题】:EXECUTE IMMEDIATE results into Table Type 【发布时间】:2019-10-23 12:49:48 【问题描述】:

我需要让 EXECUTE IMMEDIATE 将其结果返回到表类型(AS TABLE OF)

如果立即执行返回单个值,我可以使用“INTO somevariable”保存结果

但是,我的立即执行将返回一个多列的表,并且没有多少谷歌搜索可以帮助我弄清楚!

首先我创建类型

CREATE OR REPLACE TYPE T_VALIDITY_RECORD AS OBJECT (
   TIME_COL  DATE,
   VALUE_COL NUMBER
);
/

CREATE OR REPLACE TYPE T_VALIDITY_TABLE AS TABLE OF T_VALIDITY_RECORD;
/

然后我尝试代码

DECLARE
   RET_TABLE   T_VALIDITY_TABLE;
BEGIN

EXECUTE IMMEDIATE 'SELECT my_date,
                          my_numbers  
                   FROM   my_table
                   WHERE  somthing = somthingelse' INTO RET_TABLE;
END;

这只是一个非常简化的例子,真正的代码会做(会做其他事情)

我尝试了各种方法,例如 BULK COLLECT INTO 等,但似乎无法正常工作。

我收到以下错误:

错误报告 ORA-00932:不一致的数据类型:预期 - 得到 - ORA-06512:在第 5 行 00932. 00000 - “不一致的数据类型:预期的 %s 得到了 %s” *原因: *行动:

【问题讨论】:

【参考方案1】:

您需要BULK COLLECT INTO,并且需要收集T_VALIDITY_OBJECT 的实例,而不是NUMBERDATE 值对。

Oracle 设置

CREATE OR REPLACE TYPE T_VALIDITY_RECORD AS OBJECT (
   VALUE_COL NUMBER,
   TIME_COL  DATE
);
/

CREATE OR REPLACE TYPE T_VALIDITY_TABLE AS TABLE OF T_VALIDITY_RECORD;
/

CREATE TABLE my_table ( my_date, my_number, something ) AS
SELECT 1, DATE '2019-01-01', 1 FROM DUAL UNION ALL
SELECT 2, DATE '2019-01-02', 1 FROM DUAL UNION ALL
SELECT 3, DATE '2019-01-03', 1 FROM DUAL;

PL/SQL

DECLARE
  RET_TABLE   T_VALIDITY_TABLE;
BEGIN
  EXECUTE IMMEDIATE 'SELECT T_VALIDITY_RECORD( my_date, my_number )
                     FROM   my_table
                     WHERE  something = :value'
    BULK COLLECT INTO RET_TABLE
    USING 1;

  FOR i IN 1 .. RET_TABLE.COUNT LOOP
    DBMS_OUTPUT.PUT_LINE( i || ': ' || ret_table(i).time_col || ', ' || ret_table(i).value_col );
  END LOOP;
END;
/

输出

1: 2019-01-01 00:00:00, 1 2: 2019-01-02 00:00:00, 2 3: 2019-01-03 00:00:00, 3

db小提琴here

【讨论】:

【参考方案2】:

一些问题:

您将两列提取到一个结构中,该结构只有一个元素,由两个值组成。

另外,如果您的选择可以提供多于一行,则需要BULK COLLECT

如果您在这里不需要严格的动态 sql,则可以使用纯 SQL 查询:

DECLARE
   RET_TABLE   T_VALIDITY_TABLE;
BEGIN    
    SELECT T_VALIDITY_RECORD(my_date, my_numbers  )
          bulk collect INTO RET_TABLE
   FROM   my_table ;
END;

如果因为其他原因需要动态sql:

DECLARE
   RET_TABLE   T_VALIDITY_TABLE;
BEGIN
    execute immediate ' SELECT T_VALIDITY_RECORD(my_date,
                              my_numbers  )
                        FROM   my_table'   
          bulk collect INTO RET_TABLE;                   
END;

【讨论】:

谢谢,但我上面的例子被简化了,我需要使用立即执行(因为我正在动态创建 SQL 部分)有没有办法使用立即执行来实现?

以上是关于立即执行结果到表类型的主要内容,如果未能解决你的问题,请参考以下文章

从给定数据库中选择所有表时,如何将 [dbo] 前缀附加到表名?

将表数据类型从 SQL Server 转换为 Oracle 并将动态 SQL 数据插入到表数据类型

PHP:将变量绑定到表类型输出参数

T-SQL:生成数字组合并保存到表中

使用传递给过程的动态表名立即执行

Oracle 立即执行 DDL 和嵌套表