Come migrare le stored procedure di SQL Server utilizzando tabelle temporanee o variabili di tabella su Oracle?


9

Lo sviluppatore di C # incoraggiato dalla direzione a scrivere le stored procedure di SQL Server spesso produce procedure come questa

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;

Le singole affermazioni sono piuttosto semplici e questo metodo consente loro di produrre risultati corretti.

Spesso il mio compito è migrare tali procedure su Oracle.

Ammettiamo i seguenti fatti.

  • Le diverse tabelle temporanee in SQL Server sono completamente indipendenti e possono avere qualsiasi struttura ad hoc.
  • Le tabelle comuni globali Oracle sono oggetti globali e tutti gli utilizzi condividono in gran parte la stessa struttura di tabelle. La modifica di questa struttura è impossibile, mentre viene utilizzata ovunque.

Una delle cose che ho imparato da un dba di Oracle è stata quella di evitare l'uso di tabelle temporanee ogni volta che è possibile. Anche le prestazioni sul server SQL beneficiano di tali modifiche.

Sostituire i singoli inserti con i sindacati

Nel caso più semplice, quanto sopra può essere trasformato in qualcosa del genere

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

Uso di funzioni

Entrambe le funzioni scalari e le funzioni con valori di tabella possono aiutare a trasformare la procedura in una singola query del modulo precedente.

Espressioni di tabella comuni, ovvero il factoring di subquery

Il factoring di subquery è quasi il migliore che Oracle abbia da offrire per evitare tabelle temporanee. Usarlo la migrazione di SQL Server a Oracle è di nuovo piuttosto semplice. Ciò richiede SQL Server 2005 e versioni successive.


Queste modifiche migliorano la versione di SQL Server e in molti casi rendono semplice la migrazione. In altri casi il ricorso a tabelle temporanee globali consente di eseguire la migrazione in un tempo limitato, ma è meno soddisfacente.


Esistono altri modi per evitare l'uso di tabelle temporanee globali in Oracle?


3
Dirò che un codice del genere è indicativo del modo di pensare procedurale e non impostato. E queste sono tabelle temporanee locali con un singolo #. Sono un dirigente e mi spezzerei le gambe se lo vedessi entrare in produzione :-)
gbn

Sono completamente d'accordo
bernd_k,

@gbn - Il PL / SQL idiomatico tende ad essere un po 'più procedurale del T-SQL idiomatico. Le tabelle temporanee consentono di eseguire quasi tutto nelle operazioni impostate in T-SQL. PL / SQL ha operazioni di cursore parallele e molte più funzionalità per l'ottimizzazione del codice procedurale.
ConcernedOfTunbridgeWells

Risposte:


3

Un modo per farlo sarebbe tipi di oggetti , in questo caso il tipo sarebbe analogo al tuo #t1. Quindi dovrebbe essere definito da qualche parte ma non dovrebbe essere globale, potrebbe essere anche per schema o per procedura. Innanzitutto, possiamo creare un tipo:

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.

Ora imposta alcuni dati di esempio:

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.

E crea una funzione su questi dati restituendo il nostro tipo "temporaneo":

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.

E infine:

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

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

Come puoi vedere, questo è piuttosto goffo (e utilizza pseudo-funzioni di raccolta , che è una caratteristica oscura il più delle volte!), Come dico sempre, il porting da DB a DB non riguarda semplicemente la sintassi e le parole chiave nei loro dialetti SQL , la vera difficoltà si presenta in diverse ipotesi sottostanti (nel caso di SQL Server, che i cursori sono costosi e il loro uso evitato / risolto a tutti i costi).


3

Se l' opzione case non è abbastanza flessibile, è possibile raccogliere collettivamente i dati nella procedura e manipolare gli array.

--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, ma questo non restituisce un set di risultati (se a SELECTè l'ultima cosa in un proc memorizzato T-SQL, ecco cosa restituisce)
Gaius

Se questo blocco di codice fosse trasformato in una procedura, è possibile restituire l'array o aprire gli array come cursore e passare il cursore indietro, oppure renderlo una funzione e reindirizzare le righe. Ognuno di questi sarebbe simile, ma che dovresti usare dipenderebbe dalla situazione.
Leigh Riffel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.