【问题标题】:A replacement for a temporary table in OracleOracle 中临时表的替代品
【发布时间】:2014-04-23 14:18:23
【问题描述】:

在存储过程/代码块 (SP/CB) 中,我需要一种方法来存储查询的中间结果(我使用的是 Oracle 11g)。这个想法是我选择一些数据,将它们存储(在一个变量中),然后在我的 SP/CB 中我在其他查询中使用它们。并且不想为此创建任何架构级别的对象(类型,甚至更少——表)。

在 MS SQL 中,临时表就可以了,但在 Oracle 中,它不是一个选项,因为在 Oracle 中,临时表是在模式级别创建的。对象和集合可以,但我也必须在模式级别创建对象类型。接下来,有“嵌套表”选项:

DECLARE
   TYPE MyRowType   IS RECORD (<some fields here>);
   TYPE MyTableType IS TABLE OF MyRowType;
   myTable          MyTableType;

我可以通过 BULK COLLECT INTO 将所需的任何数据选择到 myTable 中,但我无法实现的是从 myTable 中选择数据。

SELECT * FROM myTable WHERE <some constraint>

这会失败并显示没有这样的表“myTable”的消息。另一种变体:

SELECT * FROM table(myTable) WHERE <some constraint>

-- 也失败(它说 myTable 不是嵌套表)。

我不能使用 WITH 子句的原因是我需要来自 myTable 的数据的查询分散在整个 SP 中。我能想到的唯一选择是创建 MyTableType(类似于 CREATE OR REPLACE TYPE MyTableType AS TABLE OF MyRowType),但这会在 DB 方案级别创建一个对象。

所以基本上,有人可以指出一个解决方法,这样我就不必创建任何永久对象并使用本地定义的类型和对象进行管理?

【问题讨论】:

  • 为了创建select,您需要一个数据库对象。
  • 在 Oracle 12c 中,可以使用 SELECT * FROM table(myTable) 而无需事先在 DB Schema 中创建 TYPE。
  • 为什么不能创建临时表?您显然已经可以运行CREATE PROCEDURE(它是在“模式级别”创建的),那么为什么不能运行create temporary table?是什么阻止您创建更多“模式级别”对象?您的表也是在“模式级别”创建的...
  • 全球临时表也许是您的答案。因为您认为自己无法使用 Oracle 已经提供的代码而维护代码行是错误的、低效的,并且通常会成为公司的噩梦。
  • 为什么不在这种情况下使用“流水线和并行表函数”?

标签: sql oracle temp-tables


【解决方案1】:

您可以使用流水线函数来执行此操作。例如:

CREATE OR REPLACE package TEST_PKG AS
    TYPE t_num_tab IS TABLE OF number;
    num_tab t_num_tab;

    function get_nums(i_cnt in number) return t_num_tab pipelined;

    procedure run_test;

    procedure init_num_tab;

END;

还有身体:

CREATE OR REPLACE package body TEST_PKG AS

    FUNCTION get_nums(i_cnt in number) 
    return t_num_tab pipelined IS
        l_cnt number := 0;
    BEGIN
        if (num_tab.count = 0) then
            return;
        end if;
        for i in num_tab.first .. num_tab.last
        loop
            l_cnt := l_cnt + 1;
            if (l_cnt > i_cnt) then
                return;
            end if;
            pipe row(i);
        end loop;
    END;

    PROCEDURE run_test IS
        l_my_local_num_tab  t_num_tab;
    BEGIN

        select * 
        bulk collect into l_my_local_num_tab
        from table (get_nums(5));

        for i in 1 .. l_my_local_num_tab.count
        loop
            dbms_output.put_line('Value is: ' || i);
        end loop;

    END run_test;


    PROCEDURE init_num_tab IS
    BEGIN
      select level
      bulk collect into num_tab
      from dual
      connect by level <= 10;
    END init_num_tab;

    -- INIT tables
    BEGIN
       init_num_tab;
END;

过程 run_test 显示了在包中的使用。外包装会类似:

select * from table(test_pkg.get_nums(5));

输出:

COLUMN_VALUE
1
2
3
4
5

【讨论】:

    猜你喜欢
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    相关资源
    最近更新 更多