如何将使用临时表或表变量的 SQL Server 存储过程迁移到 Oracle?

ber*_*d_k 9 sql-server-2005 oracle migration stored-procedures

受管理层鼓励编写 SQL Server 存储过程的 C# 开发人员经常会产生这样的过程

create table #t1 (...);
insert into #t1 Select ... from table_a where ...;
insert into #t1 Select ... from table_b where ...;
update #t1 Set ... = ... where ...
Select * from #t1;
Run Code Online (Sandbox Code Playgroud)

单个语句相当简单,这种方法使它们产生正确的结果。

我的任务通常是将这些过程迁移到 Oracle。

让我们面对以下事实。

  • SQL Server 中不同的临时表是完全独立的,可以有任何临时结构。
  • Oracle 全局公用表是全局对象,所有用途都共享相同的表结构。修改此结构是不可能的,但它可以在任何地方使用。

我从 Oracle dba 那里学到的一件事是尽可能避免使用临时表。甚至 SQL 服务器上的性能也受益于此类修改。

用联合替换单个刀片

在最简单的情况下,上面的可以转换成类似

select case when ... then ... end, ... from table_a where ...
union
select case when ... then ... end, ... from table_b where ...
Order by ...;
Run Code Online (Sandbox Code Playgroud)

函数的使用

标量函数和表值函数都有助于将您的过程转换为上述形式的单个查询。

公用表表达式又名子查询因子分解

子查询因式分解几乎是 Oracle 为避免临时表而提供的最佳方法。使用它,将 SQL Server 迁移到 Oracle 再次变得相当容易。这需要 SQL Server 2005 及更高版本。


这些修改改进了 SQL Server 版本,并且在许多情况下使迁移直接进行。在其他情况下,使用全局临时表可以在有限时间内进行迁移,但不太令人满意。


是否有其他方法可以避免在 Oracle 中使用全局临时表?

Gai*_*ius 3

实现此目的的一种方法是对象类型,在这种情况下,类型将类似于您的#t1. 因此,它需要在某个地方定义,但不需要是全局的,甚至可以是每个模式或每个过程。首先,我们可以创建一个类型:

SQL> create or replace type t1_type as object (x int, y int, z int)
  2  /

Type created.

SQL> create or replace type t1 as table of t1_type
  2  /

Type created.
Run Code Online (Sandbox Code Playgroud)

现在设置一些示例数据:

SQL> create table xy (x int, y int)
  2  /

Table created.

SQL> insert into xy values (1, 2)
  2  /

1 row created.

SQL> insert into xy values (3, 4)
  2  /

1 row created.

SQL> commit
  2  /

Commit complete.
Run Code Online (Sandbox Code Playgroud)

并在此数据上创建一个函数,返回我们的“临时”类型:

SQL> create or replace function fn_t1 return t1 as
  2  v_t1 t1 := t1();       -- empty temporary table (really an array)
  3  v_ix number default 0; -- array index
  4  begin
  5  for r in (select * from xy) loop
  6  v_ix := v_ix + 1;
  7  v_t1.extend;
  8  v_t1(v_ix) := t1_type(r.x, r.y, (r.x + r.y));
  9  end loop;
 10  return v_t1;
 11  end;
 12  /

Function created.
Run Code Online (Sandbox Code Playgroud)

最后:

SQL> select * from the (select cast (fn_t1 as t1) from dual)
  2  /

         X          Y          Z
---------- ---------- ----------
         1          2          3
         3          4          7
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这非常笨重(并且使用集合伪函数,这在最好的情况下也是一个晦涩的功能!),正如我总是说的,从数据库移植到数据库不仅仅是关于 SQL 方言中的语法和关键字,真正的困难来自于不同的基本假设(就 SQL Server 而言,游标非常昂贵,并且不惜一切代价避免/解决它们的使用)。