Jak przeprowadzić migrację procedur przechowywanych programu SQL Server przy użyciu tabel tymczasowych lub zmiennych tabel do Oracle?

9

Programista C # zachęcony przez kierownictwo do pisania procedur przechowywanych SQL Server często tworzy takie procedury

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;

Pojedyncza instrukcja jest raczej prosta i ta metoda sprawia, że ​​dają one prawidłowe wyniki.

Często moim zadaniem jest migracja takich procedur do Oracle.

Spójrzmy na następujące fakty.

  • Różne tabele tymczasowe w SQL Server są całkowicie niezależne i mogą mieć dowolną strukturę ad hoc.
  • Globalne wspólne tabele Oracle są obiektami globalnymi i wszystkie zastosowania mają tę samą strukturę tabel. Modyfikacja tej struktury jest niemożliwa, ponieważ jest używana w dowolnym miejscu.

Jedną z rzeczy, których nauczyłem się od Oracle dba, było unikanie używania tabel tymczasowych, gdy tylko jest to możliwe. Nawet wydajność na serwerze SQL korzysta z takich modyfikacji.

Zastąp poszczególne wkładki związkami

W najprostszym przypadku powyższe można przekształcić w coś podobnego

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

Korzystanie z funkcji

Zarówno funkcje skalarne, jak i funkcje cenione w tabeli mogą pomóc w przekształceniu procedury w pojedyncze zapytanie powyższej formy.

Typowe wyrażenia tabelowe zwane faktoringiem podzapytania

Faktoring podzapytania to prawie najlepsza oferta Oracle, aby uniknąć tymczasowych tabel. Za jego pomocą migracja SQL Servera do Oracle jest znów dość łatwa. Wymaga to programu SQL Server 2005 i nowszych wersji.


Te modyfikacje poprawiają wersję programu SQL Server, a w wielu przypadkach migracja jest prosta. W innych przypadkach zastosowanie globalnych tabel tymczasowych umożliwia migrację w ograniczonym czasie, ale jest mniej satysfakcjonujące.


Czy istnieją inne sposoby na uniknięcie korzystania z globalnych tabel tymczasowych w Oracle?

bernd_k
źródło
3
Powiem, że taki kod wskazuje na procesowe myślenie nie oparte na ustawieniach. I to są lokalne tabele tymczasowe z jednym #. Jestem
zarządcą
Zgadzam się całkowicie
bernd_k,
@gbn - Idiomatic PL / SQL jest zwykle bardziej proceduralny niż idiomatyczny T-SQL. Tabele temp pozwalają na wykonanie prawie wszystkiego w op operacjach w T-SQL. PL / SQL ma równoległe opcje kursora i wiele innych funkcji do optymalizacji kodu proceduralnego.
ConcernedOfTunbridgeWells,

Odpowiedzi:

3

Jednym ze sposobów, aby to zrobić, byłyby typy obiektów , w tym przypadku typ byłby podobny do twojego #t1. Musiałby więc być gdzieś zdefiniowany, ale nie musiałby być globalny, mógłby to być nawet schemat lub procedura. Najpierw możemy stworzyć typ:

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.

Teraz skonfiguruj przykładowe dane:

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.

I utwórz funkcję nad tymi danymi, zwracając nasz „tymczasowy” typ:

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.

I w końcu:

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

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

Jak widać, jest to dość niezgrabne (i używa pseudo-funkcji kolekcji , co jest w najlepszym razie niejasną funkcją!), Jak zawsze mówię, przenoszenie z DB do DB nie polega tylko na składni i słowach kluczowych w ich dialektach SQL , rzeczywista trudność wiąże się z różnymi założeniami (w przypadku SQL Server, że kursory są drogie, a ich używania unikano / obchodzono się za wszelką cenę).

Gajusz
źródło
3

Jeśli opcja przypadku nie jest wystarczająco elastyczna, możesz zbiorczo zebrać dane w swojej procedurze i manipulować tablicą (tablicami).

--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
źródło
+1, ale to nie zwraca zestawu wyników (jeśli a SELECTjest ostatnią rzeczą w proc przechowywanym w T-SQL, to właśnie to zwraca)
Gaius
Jeśli ten blok kodu zostałby przekształcony w procedurę, można zwrócić tablicę lub otworzyć tablice jako kursor i przekazać kursor z powrotem, a nawet ustawić funkcję i przesunąć wiersze z powrotem. Każdy z nich byłby podobny, ale którego należy użyć, zależy od sytuacji.
Leigh Riffel,