Comment migrer des procédures stockées SQL Server à l'aide de tables temporaires ou de variables de table vers Oracle?


9

Le développeur C # encouragé par la direction à écrire des procédures stockées SQL Server produit souvent des procédures comme celle-ci

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;

Les instructions simples sont plutôt simples et cette méthode leur permet de produire des résultats corrects.

Souvent, ma tâche consiste à migrer ces procédures vers Oracle.

Faisons face aux faits suivants.

  • Les différentes tables temporaires de SQL Server sont complètement indépendantes et peuvent avoir n'importe quelle structure ad hoc.
  • Les tables communes globales Oracle sont des objets globaux et toutes les utilisations partagent la même structure de table. La modification de cette structure est impossible, alors qu'elle est utilisée n'importe où.

L'une des choses que j'ai apprises d'une base de données Oracle, était d'éviter l'utilisation de tables temporaires chaque fois que cela est possible. Même les performances sur SQL Server bénéficient de telles modifications.

Remplacer les inserts individuels par les syndicats

Dans le cas le plus simple, ce qui précède peut être transformé en quelque chose comme

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

Utilisation des fonctions

Les fonctions scalaires et les fonctions table peuvent aider à transformer votre procédure en une seule requête du formulaire ci-dessus.

Expressions de table communes aka Factorisation de sous-requête

L'affacturage de sous-requête est presque le meilleur qu'Oracle puisse offrir pour éviter les tables temporaires. En l'utilisant, la migration de SQL Server vers Oracle est encore une fois assez facile. Cela nécessite SQL Server 2005 et supérieur.


Ces modifications améliorent la version de SQL Server et, dans de nombreux cas, facilitent la migration. Dans d'autres cas, le recours à des tables temporaires globales permet de faire la migration dans un temps borné, mais il est moins satisfaisant.


Existe-t-il d'autres moyens d'éviter l'utilisation de tables temporaires globales dans Oracle?


3
Je dirai qu'un code comme celui-ci indique une réflexion procédurale non basée sur un ensemble. Et ce sont des tables temporaires locales avec un seul #. Je suis manager et je me casserais les jambes si je voyais ça entrer en production :-)
gbn

Je suis entièrement d'accord
bernd_k

@gbn - Le PL / SQL idiomatique a tendance à être un peu plus procédural que le T-SQL idiomatique. Les tables temporaires permettent de faire presque tout dans les opérations définies dans T-SQL. PL / SQL a des opérations de curseur parallèles et beaucoup plus de fonctionnalités pour optimiser le code procédural.
ConcernedOfTunbridgeWells

Réponses:


3

Une façon de le faire serait les types d'objets , dans ce cas, le type serait analogue à votre #t1. Il devrait donc être défini quelque part, mais il ne serait pas nécessaire qu'il soit global, il pourrait même être par schéma ou par procédure. Tout d'abord, nous pouvons créer un type:

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.

Configurez maintenant quelques exemples de données:

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.

Et créez une fonction sur ces données en retournant notre type "temporaire":

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.

Et enfin:

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

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

Comme vous pouvez le voir, c'est assez maladroit (et utilise des pseudo-fonctions de collection , ce qui est une fonctionnalité obscure dans le meilleur des cas!), Comme je le dis toujours, le portage de DB à DB n'est pas seulement une question de syntaxe et de mots-clés dans leurs dialectes SQL , la vraie difficulté réside dans différentes hypothèses sous-jacentes (dans le cas de SQL Server, que les curseurs sont chers et que leur utilisation est évitée / contournée à tout prix).


3

Si l' option de cas n'est pas suffisamment flexible, vous pouvez collecter en masse les données dans votre procédure et manipuler le ou les tableaux.

--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, mais cela ne renvoie pas de jeu de résultats (si a SELECTest la dernière chose dans un proc stocké T-SQL, c'est ce qu'il renvoie)
Gaius

Si ce bloc de code était transformé en une procédure, vous pourriez retourner le tableau ou ouvrir les tableaux en tant que curseur et renvoyer le curseur, ou même en faire une fonction et rediriger les lignes. Chacun d'eux serait similaire, mais que vous devriez utiliser dépendrait de la situation.
Leigh Riffel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.