Virtabs: Schreibbare Views!

Für die salopp formulierte Anforderung “in Views mit mehreren Tabellen schreiben” muß zunächst eine verständliche Semantik definiert werden: Was soll eigentlich mit den Basistabellen der View passieren, wenn man “in eine View schreibt” ?

Beteiligte SQL-Objekte

Das definierte Verfahren wird durch folgende serverseitige SQL-Objekte implementiert, deren SQL-Code automatisch aus einer Beschreibung der entsprechenden Virtab erzeugt werden :

  1. Eine View (“Virtab-View”) , die das SELECT auf der Virtab durchführt
  2. Eine in stored procedure (“Virtab-Insert-Prozedure”), die INSERT auf der Virtab durchführen kann.
    Diese und die folgenden Prozeduren werden in der ORACLE-Sprache PL/SQL erzeugt.
  3. Eine stored procedure (“Virtab-Update-Prozedure”), die UPDATE auf der Virtab durchführen kann.
  4. Eine stored procedure (“Virtab-Delete-Prozedure”), die DELETE auf der Virtab durchführen kann.
  5. Drei Trigger auf der Virtab-View, die bewirken, das die SQL-Anweisunen “INSERT INTO virtab_view”, “UPDATE virtab_view” und  “DELETE FROM virtab_view” die entsprechenden Virtab-Procs aufrufen.

Die eigentliche Implementierung des Virtab-Konzeptes findet in den drei Virtab-Prozeduren statt. View und Trigger stellen eigentlich nur ein Zugriffs-Interface dar. Jedes INSERT, UPDATE oder DELETE wirkt auf genau einen Record der Virtab-View, dieser Datensatz soll von einem nachfolgenden SELECT wieder zurückgegeben werden. An die Virtabs-Prozeduren werden alle Spalten des betroffenen Records der Virtab-View als Parameter übergeben.

Durch die Anweisung

    INSERT INTO v_depts(regional_group, name, street city, state, zip_code)
    VALUES ('Dallas', 'research', '3 Walnut Ave', 'Dallas', 'TX','25712') ;

erfolgt also folgender Prozeduraufruf (die Insert-Prozedure der Virtab “depts” heisst “pi_deps”):

    EXEC pi_depts('Dallas', 'research', '3 Walnut Ave', 'Dallas', 'TX', '25712')

Funktion der Prozeduren: Lokalisierung von Records

Eine Virtabdefinition besteht im Kernt, wie jede View-Definition, aus einem Netz aus Master- und Detailtabellen, wobei Tabellen gleichzeitig Master und Detail sein können. Die Tabellen sind durch Fremdschlüssel miteinander verbunden.

Eine INSERT/UPDATE/DELETE -Operation auf einer Virtab bedeutet einfach, dass die entsprechende Aktion auf jeder einzelnen Basistabelle durchgeführt wird, wobei die Vernetzung der Tabellen untereinander erhalten bleiben soll. Dazu ist es nötig, dass für jede Basistabelle ein aktueller, zu bearbeitender Datensatz(record) gesucht wird (bei INSERT wird zwar kein vorhandener Datensatz bearbeitet, es muss aber sichergestellt werden, dass der Datensatz noch nicht existiert).

Ein Basistabellen-Datensatz kann nur mit den Spalteninformationen gesucht (=”lokalisiert”) werden, die an die Virtab-Prozedur übergeben wurden, die also als Spalten der Virtab definiert wurden.

Eine Virtab muss für jede Basistabelle
ausreichende Schlüsselinformation in ihren Spalten enthalten.

Es muß also für jede Basistabelle eine Spalte in der Virtab existieren, die deren Primärschlüssel oder einen Zweitschlüssel enthält. Ausnahmen von dieser Regel werden weiter unten und im Referenzteil dargestellt.

Beispiel: Die Virtab “deps” ist im Definitionsfile wie folgt definiert:

VIRTUALTABLE DEPTS
  COLUMN REGIONAL_GROUP// in der ganzen DB gibts nur eine Spalte
// REGIONAL_GROUP: keine weiteren Angaben noetig
  COLUMN DEPARTMENT_NAME = DEPARTMENT.NAME // Umbenennung gegenueber DB.
  // Spalten auf Mastertable ADDRESS
  COLUMN         street
  COLUMN         city
  COLUMN         state
  COLUMN         zip_code
;

Sie enthält die Basistabellen LOCATION, DEPARTMENT und ADDRESS, wie auch an der erzeugten View “vt_deps” zu sehen ist:

CREATE VIEW vt_depts AS
SELECT regional_group, department.name department_name,
       street, city, state, zip_code
  FROM location, department, address
 WHERE location.location_id = department.location_id
   AND department.address_id = address.address_id;

In der Definition der Demo-Datenbank sind die Primärschlüssel mit PRIMARYKEY und die benutzbaren Zweitschlüssel mit IDENTIFYING gekennzeichnet.

Das Beispiel ist gleich etwas anspruchsvoller: Die Records der drei Basistabellen werden hier nämlich über verschiedene Mechanismen lokalisiert. Es werden völlig sichtbarer Zweitschlüssel, teilweise sichtbarer Zweitschlüssel aus zwei Feldern und ein unsichtbarer Zweitschlüssel verwendet.

Basistabelle

Record
lokalisierbar
durch Feld(er)

Bemerkung

LOCATION

regional_group

Sichtbarer Zweitschlüssel (IDENTIFYING).

DEPARTMENT

name, location_id

Der Zweitschlüssel wird aus zwei Felder gebildet: name ist sichtbarer Zweitschlüssel.
location_id ist ein Fremdschlüssel, der auch als Zweitschlüssel fungiert ( “DEPARTMENT.name” muss nur innerhalb einer LOCATION eindeutig sein).
location_id ist bekannt, wenn der Master LOCATION lokalisiert wurde.

ADDRESS

address_id

In der Virtab nicht sichtbarer, aber intern benutzter Fremdschlüssel. Für Spalte “address_id” ist ein Wert bekannt, sobald ein Record von LOCATION lokalisiert wurde. Daher brauchen “address_id” nicht vom Anwender gesetzt zu werden.

Ein Record aus ADDRESS ist also lokalisierbar, obwohl keiner seiner Schlüsselfelder Teil der Virtab ist. Die Abhängigenkeiten der verschVoraussetzung ist, das

Da für die Lokalisierung von Records auch Schlüsselverbindungen zu Mastertabellen herangezogen werden können (ein Fremdschlüssel darf auch mit IDENTIFYING markiert werden), müssen die Virtab-Procs das Lokalisieren im allgemeinen von Basistabellen-Records von Mastertabellen in Richtung Detailtabellen vornehmen. Ist ein Record einer Mastertabelle lokalisiert wurden, ist zugleich der Primärkey des Masterrecords bekannt. Dieser bildet zugleich den Wert von Fremdschlüsseln in den Detailtabellen.
Umgekehrt ist der Primärkey eines Masters bekannt, wenn schon ein Detail lokalisiert wurde. ER2SQL verzichtet aber bei der “Lokalisierungs-Sortierung” nach Möglichkeit auf die Nutzung dieses Mechanismus.

Das ER-Diagramm der Datenbank muß sortierbar sein, darf also keine Master-Detail-Hierarchieschleifen enthalten.

Für jede Basistabelle muss eine Primärkey-Spalte existieren.

Diese Forderungen sind aber normalerweise in jeder Datenbank erfüllt.

Das Sortieren des Basistabellen-Netzwerkes und das Lokalisierung von Records stellt den anspruchsvolleren Teil der Virtabprozeduren dar. Er ist im wesentlichen für alle drei Prozeduren gleich.

Funktion der Prozeduren: INSERT

In der Insert-Prozedur stellt es keinen Fehler dar, wenn ein Record in einer Basistabelle nicht lokalisiert werden kann: dann wird er neu in die Basistabelle eingetragen. Der neue Datensatz benötigt einen neuen Wert für seinen Primärschlüssel. Wenn die Primärschlüsselspalte nicht Teil der Virtab ist, oder dort NULL übergeben wird, gewinnt die Prozedur den Wert unter ORACLE aus einer Sequenz mit festem Namen.

Für jeden Primärschlüssel muss eine SEQUENCE mit Namen
 “SEQ_<pk_name>” in der Datenbank vorhanden sein.

Der neu gewonnene Primärschlüsselwert wird über die Prozedurparameter zurückgegeben, und kann von der Anwendung gleich weiterverarbeitet werden.

Beispiel:

INSERT INTO vt_depts (regional_group,department,address,city,state,zip_code)
VALUES ('Dallas','research','3 Walnut ave','Dallas','TX','25712') ;

bewirkt die Ausführung folgender drei Anweisungen auf den Basistabellen (jedenfalls auf einer leeren Datenbank) :

  1. INSERT INTO location (location_id,regional_group)
    VALUES (seq_location_id.NEXTVAL,'Dallas');
  2. INSERT INTO address (address_id,street,city,state,zip_code)
    VALUES (seq_address_id.NEXTVAL,'3 Walnut ave','Dallas','TX','25712') ;
  3. INSERT INTO department (department_id, name,location_id,address_id)
    VALUES (seq_department_id.NEXTVAL,'research',gemerkte_location_id, gemerkte_address_id);

 

Funktion der Prozeduren: UPDATE

UPDATE funktioniert ähnlich: für jede Basistabelle muss ein Record gesucht werden. Anschliessen kann der Record aktualisiert werden. Da an die Update-Prozedur allerdings nur der gewünschte neue Datensatz übergeben wird (und nicht auch die vorhandene Version), können Schlüsselfelder für Basistabellen mit UPDATE nicht geändert werden. (Ausnahmen siehe Referenzteil).

Wenn ein Record einer Basistabelle nicht lokalisiert werden kann, ist das ein Fehler.

Der SQL-Befehl “UPDATE ... WHERE ... “ auf einer View führt implizit ein SELECT durch. Die Prozedur wird einmal für jeden Datensatz ausgeführt, der durch die WHERE-Bedingung ausgewählt wird. Auch wenn mit “UPDATE ... WHERE ...”nur ein Teil der Virtabspalten gesetzt wird, erhält doch jeder Parameter der Update-Prozedur einen Wert aus dem neuen View-Record.

Funktion der Prozeduren: DELETE

DELETE ist funktional am einfachsten: Erst wird für jede Basistabelle ein Record lokalisiert, dann wird dieser Record (über die ermittelten Primärschlüssel) gelöscht. Es wird in umgekehrter Reihenfolge gelöscht: zuerst Detailtabellen, dann die Mastertabellen.

Die Delete-Prozedur bietet zusätzlich folgenden Service: Sie überprüft beim Löschen einer Tabelle optional, ob auf diese Tabelle noch von anderen Tabellen aus Referenzen bestehen. Falls das so ist, wird der Eintrag nicht gelöscht, sondern es gibt eine Fehlermeldung, die den referenzierenden Tabellenrecord benennt. Dies ist beim Debugging eine wertvolle Hilfe, da ORACLE bei einer Constraint-Verletzung nur allgemeine Fehlermeldungen produziert.

Funktion der Applikations-Interfaces

Da schon serverseitig die View und die Prozeduren durch Trigger zu einer Einheit verbunden sind, können Virtabs eigentlich von allen Plattformen aus direkt wie normale Datenbanktabellen angesteuert werden. Es gibt allerdings Gründe, für verschiedene Entwicklungsumgebungen ein besonderes Virtab-Interface bereitzustellen.

  • Manche Entwicklungsumgebungen (z.B. Borland Delphi) sind so intelligent, dass sie RDBMS-Views und RDBMS-Tables voneinander unterscheiden können und das Schreiben in eine Virtab-View verbieten.
  • Für die Spalten einer Virtab können verschiedene Attribute definiert werden, die den übergebenen Spaltenwert verändern: Es wurde schon erwähnt, dass bei INSERT ein mit NULL übergebener Primärschlüssel automatisch mit einem Wert belegt wird. Wurde für eine Spalte ein Defaultwert angegeben, ist das Verhalten ähnlich.
    Diese “intelligente” Wertänderungen müssen mit den Datenmengen-Objekte der Anwendung synchronisiert werden. Die Anwendung kann zwar nach jedem INSERT ein SELECT ausführen, das Virtab-Interface synchronisiert aber zuverlässiger und ohne Neuabfrage.
  • Das Virtab-Interface stellt der Anwendung zusätzliche Informationen über Name und Eigenschaften der definierten Virtabs bereit, es dient also als auch “Virtab-Dictionary”.

Die Architekur sieht - hier für einen 2-tier - bei Einsatz eines Virtab-Interfaces so aus:

Falls Borland-Delphi als Entwicklungsumgebung für den Client verwendet wird, werden spezielle Nachfahren von TDataset (TVirtabT) zum Ansteuern der Virtab verwendet. Diese kapseln View und Prozeduren client-seitig. (Die Darstellung erfolgt hier gegenüber der obigen gedreht, “A”..”Z” bezeichnen die Tabellen im serverseitigen ER-Diagrammm).

Read more ....

Auf dieser Seite wurde nur das Grundprinzip der Virtab-Prozeduren dargestellt. Dieser Ablauf kann durch viele Optionen erweitert oder verändert werden (siehe Features und Referenzteil).

 

[Virtabs] [Positionierung] [Schreibbare Views?] [Schreibbare Views!] [Feature-Überblick] [Virtabs entwickeln] [Unterstützte Datenbanken] [Referenz] [Konzepte] [Application-Interfaces] [Struktur der Demo-DB] [Guided tour] [Beispiel-Code]