一時テーブルまたはテーブル変数を使用してSQL ServerストアドプロシージャをOracleに移行する方法


9

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;

単一のステートメントはかなり単純であり、この方法により、正しい結果が生成されます。

多くの場合、私の仕事はそのような手順をOracleに移行することです。

次の事実に直面しましょう。

  • SQL Serverの異なる一時テーブルは完全に独立しており、任意のアドホック構造を持つことができます。
  • Oracleグローバル共通テーブルはグローバルオブジェクトであり、すべての用途で同じテーブル構造を共有します。この構造はどこでも使用されていますが、変更することはできません。

Oracle dbaから学んだことの1つは、可能な場合は常に一時テーブルの使用を避けることでした。SQLサーバーのパフォーマンスでさえ、このような変更の恩恵を受けます。

個々のインサートをユニオンに置き換える

最も単純なケースでは、上記は次のようなものに変換できます。

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
そのようなコードは、手続きベースの集合ベースの考え方ではないことを示しています。そして、これらは単一の#を持つローカル一時テーブルです。私は経営者であり、それが本番
環境に

私は完全に同意します
bernd_k

@gbn-慣用的なPL / SQLは、慣用的なT-SQLよりも少し手続き型になる傾向があります。一時テーブルを使用すると、T-SQLの集合演算でほぼすべてを実行できます。PL / SQLには、並列カーソル操作と、手続き型コードを最適化するための多くの機能があります。
ConcernedOfTunbridgeWells

回答:


3

これを行う1つの方法は、オブジェクトタイプです。この場合、タイプはに類似しています#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

ご覧のように、これはかなり不格好です(そして、多くの場合、あいまいな機能であるコレクションの疑似関数を使用しています!)。 、本当の難しさは、さまざまな基本的な前提条件にあります(SQL Serverの場合、カーソルは高価であり、その使用は避けられるか、すべてのコストで回避されます)。


3

場合はケースのオプションでは、可能性柔軟十分ではありません一括収集、あなたの手順でデータと配列(複数可)を操作します。

--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

このコードブロックがプロシージャに変換された場合、配列を返すか、配列をカーソルとして開いてカーソルを返すか、関数にして行をパイプで戻すこともできます。これらはそれぞれ似ていますが、どちらを使用するかは状況によって異なります。
リーRiffel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.