如何在Oracle中使用本地临时表或使用动态SQL的替代方法?
在SQL Server中,从名为dbo.2019的表中选择所有列到名为x的本地临时表中:
CREATE TABLE #x (a int)
DECLARE @FY varchar(4) = Year(date())
EXEC ('SELECT * into #x FROM dbo.'+@FY)
之所以这样做,是因为我想使用各种信息(除年份之外,例如来自其他表或其他任何表的值)来构建非常复杂的查询,而无需很多奇怪的子查询。
SQL Server的局限性是您必须首先创建临时表,或者必须使用全局表,否则人们可能会覆盖它们。
您知道,Oracle <> MS SQL Server。后者大量使用临时表。 Oracle-通常/通常是不需要的。
但是,对于您的特定问题(“非常复杂的查询”之类的东西),这可能不是一个坏主意。根据您的Oracle数据库版本,有全局临时表(和-在最新版本中为私有)。它们如何工作?您一次创建它们并使用多次,这意味着您不应动态创建它们。尽管许多用户可以同时使用它们,但是存储在其中的数据仅对您可见。此外,在整个会话期间(如果您选择使用on commit preserve rows
选项创建数据)或在事务处理期间[on commit delete rows
)都保留数据。
例如:
SQL> create global temporary table gtt_test
2 (id number,
3 name varchar2(20))
4 on commit delete rows;
Table created.
SQL>
您可以将它们编入索引:
SQL> create index i1_gtt on gtt_test (id);
Index created.
SQL>
然后做任何你想做的事。一旦您的会话(或交易)结束,吹气!它们为空,不是数据永久存储在其中。如果明天您必须做同样的工作,桌子仍然在这里等着您。没有[[dynamic创建/删除/创建/删除(或您认为应该做的任何事情)。
因此:只需创建一次,即可在需要时使用。SQL> declare
2 l_cnt number;
3 begin
4 -- check whether table already exists
5 select count(*)
6 into l_Cnt
7 from user_tables
8 where table_name = 'TEST';
9
10 -- yes, it exists - drop it first
11 if l_cnt = 1 then
12 execute immediate 'drop table test';
13 end if;
14 -- now create it
15 execute immediate 'create table test (id number, name varchar2(20))';
16
17 -- insert some rows
18 insert into test (id, name) values (1, 'Littlefoot');
19 end;
20 /
insert into test (id, name) values (1, 'Littlefoot');
*
ERROR at line 18:
ORA-06550: line 18, column 15:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 18, column 3:
PL/SQL: SQL Statement ignored
SQL>
尽管我首先检查表是否存在(以便先删除它,然后重新创建它),但整个PL / SQL块都失败了,因为我正在尝试使用尚不存在的表(在编译时)。
因此,如果我想使用该:编写丑陋,难以调试,当心单引号问题...您真的想要避免这种情况。test
表,则在同一个PL / SQL块中的任何操作也应变为动态,这是可怕的
再次:我建议您不要动态地这样做。