Es gibt viele Gründe, Strukturen in der Datenbank aufzuräumen und reorganisieren. Sei es in gewachsenen Applikationen, sei es bei der Modernisierung oder dem Zugriff von weiteren Front-Ends auf die gleichen Datenbank Sourcen. Selbst wenn eine komplett neue Architektur aus einer Modellierung übernommen werden soll, wird recht schnell klar, dass die Datenbank-Objekte in der richtigen Reihenfolge angelegt werden müssen. Das ist zunächst offensichtlich und jedem klar. Sequences vor Tabellen, Tabellen vor Views vor PL/SQL-Funktionen und Prozeduren …

Schwieriger zu bestimmen wird es, wenn gleiche Objekt-Typen untereinander abhängig sind, z.B. wenn Typen auf Typen aufsetzen. Hier die richtige Reihenfolge zu bestimmen ist nicht immer trivial, gerade dann, wenn die Aufgabe darin besteht, in einem skript-gesteuerten Ansatz eine beliebige Vielzahl von TYPE Deklarationen zu erstellen.

Eine gute Möglichkeit bietet hier die Möglichkeit, in der Oracle Datenbank „incomplete Types“ zu erstellen:
Oracle TYPE Syntax

Durch die reine Angabe des Typ-Namen bei dem CREATE-Statement kann dieser Typ zunächst in weiteren Statements genutzt werden und die Implementierung und genaue Spezifikation kann in einem weiteren Verlauf erfolgen. Mit dieser Forward-Deklaration ist eine Ermittlung der Reihenfolge nicht mehr relevant und es können zuerst alle Typen incomplete erstellt werden, bevor die eigentliche Implementierung erfolgt. Für einzelne Skripte kann alternativ auch im „Prefix“ des Skripts sichergestellt werden, dass alle benutzten Typen in einer Forward-Deklaration zunächst angelegt werden.

In größeren Modernisierungsprojekten liegen nach einer Refakturierung die Metadaten häufig in eigenen Tabellen-Strukturen vor. Aus diesen lassen sich dann sehr leicht über Velocity/Texen die passenden Templates für die Generierung der SQL-Skripte erstellen. Bei der Forward-Deklaration der Typen kann dann eine Metadaten-Tabelle und das passende  Velocity-Template so aussehen:

SORTObject_NameObject_typeobject_value
1beispiel_otOT
2name_attribut1Rtabelle1.spalte2
3name_attribut3Nvarchar2(100)
4name_attribut4Nnumber(12,2)
5name_attribut5Tanderer_ot
6name_attribut6Cbase_type

Dabei kann innerhalb des Object_types unterschieden werden:

  • R: verweist auf den Spalten-Typ einer existenten Tabelle
  • N: normaler, simple Oracle Datentyp, z.B. Number, Date, varchar, …
  • T: Nutzt einen anderen, selbst definierten Datentypen als SubType
  • C: collection eines Base_type

In der Velocity-Datei wird dann zunächst für alle Typen die Forward-Deklaration angelegt, bevor im zweiten Loop die Implementierung erfolgt:

*#
#* Forward-Deklaration der benutzen Objekttypen *#
#foreach($row in $rows)
   #if($row.OBJECT_TYPE=="T" || $row.OBJECT_TYPE=="C")
      CREATE TYPE $row.OBJECT_VALUE;
   #end
   #if($row.OBJECT_TYPE=="C")
      CREATE TYPE ${row.OBJECT_VALUE}_COL IS TABLE OF $row.OBJECT_VALUE;
   #end
#end
#. Abschluss der notwendigen Forward-Deklarationen, 
#. um den Typen fehlerfrei erstellen zu können

CREATE OR REPLACE 
TYPE $commonsStr.upperCase($strings.concat(["ty_", $object_name]))
FORCE
/*
 OBJECT TYPE: $object_name

 Beschreibung:
#foreach($row in $rows)
   #if($row.OBJECT_TYPE=="OC")
      $commonsStr.replaceOnce($row.OBJECT_DESC,"--",">")
   #end
#end
#set($D="$")
 SVN-Info: ${D}HeadURL${D}
 : ${D}Id${D}

 Autoren:
 18.03.2015 PITSS.CON Automatische Generierung

 LEGENDE: ... > neu, Änderung, ! Bugfix, < entfernt

 HISTORIE:
 (start table)
 Vers. Wann Wer Was
 1.00 , 18.03.2015, PITSS.CON, *Neuerstellung
 (end)
*/
IS
--
OBJECT
(

#foreach($row in $rows)
   #if($row.OBJECT_TYPE =="R" || $row.OBJECT_TYPE =="N" || $row.OBJECT_TYPE =="T" || $row.OBJECT_TYPE =="C" )
      #set($last_sort="0")
      #if($last_sort==$row.SORT),#end
      #set($last_sort=$row.SORT)
      #if($row.OBJECT_TYPE =="C")
          ${row.OBJECT_NAME} ${row.OBJECT_VALUE}_COL ${row.OBJECT_DESC} 
      #else
          ${row.OBJECT_NAME} ${row.OBJECT_VALUE} ${row.OBJECT_DESC} 
      #end#end#end
...

);
/

SHOW ERRORS;