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


9

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

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;

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

通常,我的任务是将此类过程迁移到Oracle。

让我们面对以下事实。

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

我从Oracle dba中学到的一件事是避免在可能的情况下使用临时表。这样的修改甚至可以提高SQL Server的性能。

用活接头替换单个插件

在最简单的情况下,以上内容可以转换为

select case when ... then ... end, ... from table_a where ...
union
select case when ... then ... end, ... from table_b where ...
Order by ...;

功能使用

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

通用表表达式又名子查询分解

子查询分解几乎是Oracle提供的避免临时表的最佳方法。使用它,将SQL Server迁移到Oracle同样非常容易。这需要SQL Server 2005及更高版本。


这些修改改进了SQL Server的版本,并且在许多情况下使迁移更加直接。在其他情况下,诉诸于全局临时表可以在有限的时间内进行迁移,但效果不理想。


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


3
我会说这样的代码表示不基于过程的思考。这些是带有单个#的本地临时表。我是管理人员,如果看到要投入生产的话,我会断腿的:-)
gbn

我完全同意
bernd_k 2011年

@gbn-惯用的PL / SQL往往比惯用的T-SQL更具过程性。临时表使得在T-SQL中几乎可以执行set ops中的所有操作。PL / SQL具有并行游标操作和许多用于优化过程代码的功能。
ConcernedOfTunbridgeWells,

Answers:


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.

现在设置一些示例数据:

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.

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

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.

最后:

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

         X          Y          Z
---------- ---------- ----------
         1          2          3
         3          4          7

如您所见,这非常笨拙(并且使用了集合伪函数,这在大多数情况下是最好的功能!),正如我总是说的那样,从DB移植到DB不仅涉及其SQL方言中的语法和关键字。 ,真正的困难来自于不同的基本假设(在SQL Server中,游标很昂贵,并且不惜一切代价避免/避免使用游标)。


3

如果case选项不够灵活,则可以批量收集过程中的数据并处理数组。

--Setup
CREATE TABLE table_a (c1 Number(2));
CREATE TABLE table_b (c1 Number(2));
INSERT INTO table_a (SELECT rownum FROM dual CONNECT BY rownum<=4);
INSERT INTO table_b (SELECT rownum+5 FROM dual CONNECT BY rownum<=4);

--Example
DECLARE
   Type tNumberArray Is Table Of Number;
   v1 tNumberArray;
BEGIN
   SELECT c1 BULK COLLECT INTO v1 FROM (
      SELECT c1 FROM table_a
      UNION ALL
      SELECT c1 FROM table_b
      );

   For x IN v1.First..v1.Last Loop
      /* Complex manipulation goes here. */
      If (v1(x) <= 3) Then
         v1(x) := v1(x)*10;
      End If;
      DBMS_OUTPUT.PUT_LINE(v1(x));
   End Loop;
END;
/

+1,但这不会返回结果集(如果a SELECT是T-SQL存储过程中的最后一件事,那就是它返回的结果)
Gaius

如果将此代码块转换为过程,则可以返回数组或将数组作为游标打开并将游标传回,甚至使其成为函数并通过管道返回行。这些都类似,但是您应根据情况使用。
Leigh Riffel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.