Bagaimana cara memigrasi prosedur tersimpan SQL Server menggunakan tabel sementara atau variabel tabel ke Oracle?

9

Pengembang C # didorong oleh manajemen untuk menulis prosedur tersimpan SQL Server sering menghasilkan prosedur seperti ini

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;

Pernyataan tunggal agak sederhana dan metode ini membuatnya menghasilkan hasil yang benar.

Seringkali tugas saya adalah memigrasikan prosedur tersebut ke Oracle.

Mari kita hadapi fakta-fakta berikut.

  • Untuk tabel sementara yang berbeda di SQL Server sepenuhnya independen dan dapat memiliki struktur ad hoc.
  • Oracle tabel bersama global adalah objek global dan semua menggunakan banyak struktur tabel yang sama. Memodifikasi struktur ini tidak mungkin, sementara itu digunakan di mana saja.

Salah satu hal yang saya pelajari dari Oracle dba, adalah untuk menghindari penggunaan tabel sementara kapan pun memungkinkan. Bahkan kinerja pada SQL server mendapat manfaat dari modifikasi tersebut.

Ganti sisipan individu dengan serikat

Dalam kasus yang paling sederhana, hal di atas dapat diubah menjadi sesuatu seperti

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

Penggunaan fungsi

Baik fungsi skalar maupun fungsi bernilai tabel dapat membantu mengubah prosedur Anda menjadi satu kueri dari formulir di atas.

Ekspresi Common Table alias Anjak Subquery

Anjak Subquery hampir merupakan yang terbaik yang ditawarkan Oracle untuk menghindari tabel sementara. Menggunakannya migrasi SQL Server ke Oracle sekali lagi agak mudah. Ini membutuhkan SQL Server 2005 dan di atasnya.


Modifikasi ini meningkatkan versi SQL Server dan dalam banyak kasus membuat migrasi langsung. Dalam kasus lain resor ke tabel sementara global memungkinkan untuk melakukan migrasi dalam waktu terbatas, tetapi kurang memuaskan.


Apakah ada cara lebih lanjut untuk menghindari penggunaan tabel sementara global di Oracle?

bernd_k
sumber
3
Saya akan mengatakan bahwa kode seperti itu adalah indikasi dari pemikiran berdasarkan prosedur yang tidak ditetapkan. Dan ini adalah tabel temp lokal dengan # tunggal. Saya manajemen dan saya akan mematahkan kaki jika saya melihat bahwa masuk ke produksi :-)
gbn
Saya setuju sepenuhnya
bernd_k
@ gbn - PL / SQL idiomatik cenderung sedikit lebih prosedural daripada T-SQL idiomatik. Tabel temp memungkinkan untuk melakukan hampir semua yang ada di set ops di T-SQL. PL / SQL memiliki ops kursor paralel dan lebih banyak fungsi untuk mengoptimalkan kode prosedural.
ConcernedOfTunbridgeWells

Jawaban:

3

Salah satu cara untuk melakukan ini adalah Jenis Objek , dalam hal ini jenisnya akan sesuai dengan Anda #t1. Jadi itu perlu didefinisikan di suatu tempat tetapi tidak perlu global, itu bisa per-skema atau bahkan per-prosedur. Pertama, kita bisa membuat tipe:

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.

Sekarang siapkan beberapa data sampel:

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.

Dan buat fungsi atas data ini dengan mengembalikan tipe "sementara" kami:

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.

Dan akhirnya:

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

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

Seperti yang Anda lihat ini cukup kikuk (dan menggunakan koleksi pseudo-fungsi , yang merupakan fitur tidak jelas di saat terbaik!), Seperti yang selalu saya katakan, porting dari DB ke DB bukan hanya tentang sintaks dan kata kunci dalam dialek SQL mereka , kesulitan sebenarnya datang dalam asumsi dasar yang berbeda (dalam kasus SQL Server, bahwa kursor mahal dan penggunaannya dihindari / dikerjakan di semua biaya).

Gayus
sumber
3

Jika kasus opsi tidak cukup fleksibel Anda bisa bulk mengumpulkan data dalam prosedur dan memanipulasi array (s).

--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;
/
Leigh Riffel
sumber
+1, tetapi ini tidak mengembalikan set hasil (jika a SELECTadalah hal terakhir dalam T-SQL proc yang disimpan, itulah yang dikembalikan)
Gayus
Jika blok kode ini diubah menjadi prosedur, Anda dapat mengembalikan array atau membuka array sebagai kursor dan melewatkan kursor kembali, atau bahkan membuatnya berfungsi dan menyalurkan baris. Masing-masing akan serupa, tetapi yang harus Anda gunakan akan tergantung pada situasinya.
Leigh Riffel