使用与现有 table 相同的 table 结构创建 Oracle 临时 table

Creation of Oracle temporary table with same table structure to that of a existing table

如何创建与现有 table 具有相同 table 结构的全局临时 table?

我知道这个概念在 SQL 服务器中可用,例如 "select * into #temp123 from abc"。但我想在 Oracle 中执行相同的操作。

Create global temporary table mytemp 
as 
select * from myTable
where 1=2

Oracle 中的全局临时 table 与 SQL 服务器中的临时 table 非常不同。它们是永久的数据结构,只是其中的数据是临时的(限于会话或事务,取决于table 的定义方式)。

因此,使用全局临时tables 的正确方法与我们在SQL 服务器中使用临时tables 的方式有很大不同。 CREATE GLOBAL TEMPORARY TABLE 语句是一次性练习(与任何其他 table 一样)。在 Oracle 中动态删除和重新创建 table 是一种不好的做法,

鉴于创建全局临时文件 table 应该是一次性练习,使用 CREATE TABLE ... AS SELECT 语法没有真正的好处。该语句应明确定义,脚本应像任何其他 DDL 一样存储在源代码管理中。


您已标记您的问题 [oracle18c]。如果你真的在使用 Oracle 18c,你有一个新特性向你开放,private temporary tables,它更接近 SQL Server temporary tables。这些 table 是真正在内存中的,在事务或会话结束时自动删除(同样根据定义)。这些都已涵盖 in the Oracle documentation 但这里是头条新闻。

使用永久 table 的数据子集创建私有临时 table 数据 T23:

create table t23  (
    id number primary key
    , txt varchar2(24)
    );

insert into t23 
select 10, 'BLAH' from dual union all 
select 20, 'MEH' from dual union all 
select 140, 'HO HUM' from dual
/


create private temporary table ORA$PTT_t23 
on commit preserve definition
as 
select * from t23
where id > 100;

ORA$PTT前缀是必须的(虽然可以通过设置init.ora参数来改变PRIVATE_TEMP_TABLE_PREFIX,但何必呢?

之后我们可以在 table:

上执行任何常规 DML
select * from ORA$PTT_t23;

最大的限制是我们不能在静态PL/SQL中使用table。 table 在数据字典中不存在,因此 PL/SQL 编译器会抛出 - 即使对于匿名块也是如此:

declare 
    rec t23%rowtype;
begin
    select * 
    into rec
    from ORA$PTT_t23';
    dbms_output.put_line('id = ' || rec.id);
end;
/

ORA-06550: line 6, column 10: PL/SQL: ORA-00942: table or view does not exist

任何对 PL/SQL 中私有临时 table 的引用都必须使用动态 SQL 完成:

declare 
    n pls_integer;
begin
    execute immediate 'select id from ORA$PTT_t23' into n;
    dbms_output.put_line('id = ' || n);
end;
/

基本上这将它们的使用限制在 SQL*Plus(或 sqlcl 脚本,其中 运行 一系列纯 SQL 语句。所以,如果你有一个用途case which fits that, then you should check out private temporary tables. 但是,请考虑 Oracle 在许多方面与 SQL Server 不同,尤其是它的多版本一致性模型:读取器不会阻止写入器。因此,Oracle 中对临时 table 的需求要少得多。

在 SQL 服务器的语法中,table 名称中的前缀“#”(散列)#temp123 表示 - 创建只能通过访问的临时 table当前会话(“##”表示 "Global")。

要在 Oracle 中实现完全相同的结果,您可以使用 private temporary tables:

SQL> show parameter private_temp_table            

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
private_temp_table_prefix            string      ORA$PTT_

create table mytab as 
    select 1 id, cast ('aaa' as varchar2 (32)) name from dual
;

create private temporary table ora$ptt_mytab on commit preserve definition as
    select * from mytab where 1=0
;
Private TEMPORARY created.

之后您可以在 SQL 和 PL/SQL 块中使用这些 table:

declare
    r mytab%rowtype;
begin 
    insert into ora$ptt_mytab values (2, 'bbb');
    select id + 1, name||'x' into r from ora$ptt_mytab where rownum = 1;
    insert into ora$ptt_mytab values r;
end;
/
select * from mytab
union all
select * from ora$ptt_mytab;

        ID NAME                            
---------- --------------------------------
         1 aaa                             
         2 bbb                             
         3 bbbx                            

私有临时 tables 的一些重要限制:

  • 名称必须始终以参数 PRIVATE_TEMP_TABLE_PREFIX 定义的任何内容为前缀。默认为 ORA$PTT_.

  • 您不能在命名的 PL/SQL 块的静态语句中引用 PTT,例如包、函数或触发器。

  • %ROWTYPE 属性不适用于该 table 类型。

  • 您不能使用默认值定义列。