Erstellen von Views
VIEWs sind Abfragen, die in der Datenbank als Objekt fest gespeichert sind. Sie können als virtuelle Tabellen verstanden werden, deren Inhalt und Struktur auf anderen Tabellen oder Views basieren, und können in (fast) jedem SELECT-Befehl anstelle einer „echten“ Tabelle verwendet werden.
Allgemeine Hinweise
[Bearbeiten]Bei einer View wird die Abfrage in der Datenbank gespeichert, aber nicht das Ergebnis. Bei jedem neuen Aufruf der View wird die dahinterliegende Abfrage neu ausgeführt, denn sie soll ja das Ergebnis anhand der aktuellen Daten bestimmen.
Die Abfragen, auf denen Views basieren, können grundsätzlich alle Klauseln wie eine normale Abfrage enthalten. Somit ist es möglich, bestimmte Daten in einer View zu selektieren und zu gruppieren. Hierbei können die Daten aus mehreren Tabellen oder Views selektiert werden.
Je nach DBMS und Situation kann eine einzelne Klausel der View unwirksam sein oder zu unklaren Ergebnissen führen.
- Eine ORDER BY-Klausel der View wird ignoriert, wenn der SELECT-Befehl, der sie benutzt, selbst eine Sortierung verwendet.
- Bei einer Beschränkung durch LIMIT o. ä. weiß das DBMS oft nicht, nach welchen Regeln diese Beschränkung verwirklicht werden soll.
- WHERE-Bedingungen können nur fest eingebaut werden, aber nicht mit variablen Parametern.
Mit Views wird die stark differenzierte Struktur eines Auswahlbefehls vereinfacht. Die View wird mit ihrer komplexen Abfrage einmal angelegt, und die Nutzer können die Daten dieser View immer wieder abfragen.
Weiterhin können Views genutzt werden, um den Zugriff auf bestimmte Daten einzuschränken. Nutzer können Zugriff nur auf bestimmte Views bekommen. Somit lässt sich der Zugriff für einzelne Nutzer auf bestimmte Daten (Spalten und Datensätze) beschränken.
Eine View anlegen und benutzen
[Bearbeiten]Views werden mit dem Befehl CREATE VIEW mit folgender Syntax angelegt.
CREATE VIEW <View-Name> [ ( <Spaltennamen> ) ] AS <Select-Ausdruck> ;
Zu dieser Definition gehören folgende Bestandteile:
- CREATE VIEW kennzeichnet den Befehl.
- Unter <View-Name> ist eine Bezeichnung anzugeben, unter der die View in einem SELECT-Befehl angesprochen wird. Dieser Name muss eindeutig sein und darf auch kein Name einer „echten“ Tabelle sein.
- Als <Select-Ausdruck> wird ein (beliebiger) SELECT-Befehl eingetragen.
- Es wird empfohlen, möglichst bei allen Spalten mit einem Alias zu arbeiten.
- Diese können wahlweise vor dem AS in Klammern angegeben werden oder (wie üblich) Teil des <Select-Ausdruck>s sein.
Die View wird dann wie jede Tabelle benutzt, z. B. einfach:
SELECT * FROM <View-Name>
Oder auch als Teil einer komplexen Abfrage:
SELECT <irgendwas> FROM <Tabelle> JOIN <View-Name> ON /* usw. */
Eine einfache View
[Bearbeiten]Im einfachsten Fall greifen wir auf eine einfache Verknüpfung zweier Tabellen zu und verbinden dies mit einer festen Suchbedingung.
Erstelle eine View, die eine Liste aller Fahrzeugtypen deutscher Hersteller anzeigt.
CREATE VIEW Deutscher_Fahrzeugtyp
AS SELECT DISTINCT ft.Bezeichnung AS Fahrzeugtyp, fh.Name AS Hersteller
FROM Fahrzeugtyp ft
join Fahrzeughersteller fh on ft.Hersteller_ID = fh.ID
WHERE fh.Land = 'Deutschland';
Die Abfrage basiert auf den beiden Tabellen Fahrzeugtyp und Fahrzeughersteller. Es werden nur die Spalten Bezeichnung und Name abgefragt; durch die WHERE-Klausel wird das Ergebnis auf Fahrzeuge deutscher Hersteller beschränkt. Für die Spalten werden Spalten-Aliase genutzt.
Diese View wird dann wie eine „normale“ Tabellen in Abfragen genutzt.
In diesem Fall kann die ORDER BY-Klausel ebensogut Teil der View sein; das untersuchen wir später noch.
Eine View mit variabler Selektion
[Bearbeiten]Es klappt leider nicht, in eine View eine WHERE-Klausel einen (variablen) Parameter einzubauen, der erst im SELECT mit einem konkreten Wert versehen wird.
Gesucht wird eine Abfrage über die Mitarbeiter einer Abteilung; am Anfang soll der Abteilungsleiter stehen, danach alphabetisch die betreffenden Mitarbeiter. Die Nummer der Abteilung soll nicht fest vorgegeben werden, sondern variabel sein.
Auch Alternativen für das Fragezeichen führen nicht zum Ziel. Es bleibt nur ein kleiner Umweg, nämlich die Abteilung_ID in der View zu berücksichtigen und später für WHERE zu nutzen:
create view Mitarbeiter_in_Abteilung
( Pers, Name, Vorname, Geburtsdatum, Abt )
as select Personalnummer, Name, Vorname, Geburtsdatum, Abteilung_ID
from Mitarbeiter
order by Ist_Leiter, Name, Vorname;
Damit können alle Angaben einer bestimmten Abteilung geholt werden; die Spalte Abt bleibt zur Verdeutlichung stehen:
Und siehe da: zuerst kommt der Abteilungsleiter, danach die anderen Mitarbeiter in alphabetischer Reihenfolge.
Hinweis: Eine Alternative zu einer VIEW mit variabler WHERE-Bedingung ist eine „StoredProcedure“, die diese Abfrage enthält und einen Wert als Parameter entgegennimmt; sie wird in einem späteren Kapitel behandelt.
Probleme mit der Sortierung
[Bearbeiten]Ändern wir die obige View deutscher Fahrzeuge dahin, dass die Sortierung nach Hersteller fest eingebaut wird.
- Bitte beachten Sie: Wenn Sie oben die View Deutscher_Fahrzeugtyp fest gespeichert haben, müssen Sie in diesem Abschnitt einen anderen Namen verwenden oder stattdessen etwas wie CREATE OR ALTER (siehe die DBMS-Dokumentation) benutzen.
CREATE VIEW Deutscher_Fahrzeugtyp ( Typ, Firma )
AS SELECT DISTINCT ft.Bezeichnung, fh.Name as Firma
FROM Fahrzeugtyp ft
join Fahrzeughersteller fh on ft.Hersteller_ID = fh.ID
WHERE fh.Land = 'Deutschland'
order by Firma;
Bitte beachten Sie, dass in diesem Fall der Spalten-Alias Firma auch Teil des SELECT-Befehls sein muss, damit er in der ORDER BY-Klausel bekannt ist.
Jetzt wird die Liste wahlweise mit oder ohne Sortierung abgerufen:
SELECT * FROM Deutscher_Fahrzeugtyp; -- automatisch sortiert nach Firma SELECT * FROM Deutscher_Fahrzeugtyp ORDER BY Typ; -- speziell sortiert nach Typ
Views in Verbindung mit JOIN
[Bearbeiten]Die obige Verknüpfung „Fahrzeugtyp plus Hersteller“ benötigen wir in der Praxis ständig, nicht nur in der konkreten Abfrage nach deutschen Herstellern. Bisher – zum Beispiel mit OUTER JOIN – haben wir beide Tabellen separat per JOIN eingebunden, mussten aber immer auf die Art des JOINs aufpassen. Das kann man einmalig durch eine fiktive Tabelle Fahrzeugart, also eine VIEW mit den benötigten Informationen steuern.
Eine solche VIEW erfüllt mehrere Wünsche:
- Die eigentlichen Informationen werden getrennt gespeichert; es ist nicht nötig, bei jedem Fahrzeugtyp den Hersteller und sein Herkunftsland aufzuführen. Wie wir aus der Wirtschaftspolitik des Jahres 2009 wissen, kann sich ein Herkunftsland durchaus ändern; nach den Regeln der Normalisierung ist die separate Tabelle der Hersteller nicht nur sinnvoll, sondern notwendig.
- Bei jeder Abfrage des Fahrzeugtyps erhalten wir sofort auch den Hersteller.
- Jede solche Abfrage wird einfacher, weil eine Tabelle weniger benötigt wird.
- Das DBMS kennt seine VIEWs und hat sie „von Haus aus“ optimiert; also wird jede solche Abfrage auch schneller ausgeführt.
- Diese Aussage gilt nicht unbedingt bei jeder Abfrage und jedem DBMS. Aber nach allen Erkenntnissen über interne Datenbankstrukturen kann man davon ausgehen.
Das obige „einfache Beispiel“ der VIEW müssen wir nur wenig umschreiben:
Bereite eine (fiktive) Tabelle Fahrzeugart vor mit allen relevanten Informationen aus den Tabellen Fahrzeugtyp und Fahrzeughersteller.
CREATE VIEW Fahrzeugart
( ID, Bezeichnung, Hersteller, Land )
AS SELECT ft.ID, ft.Bezeichnung, fh.Name, fh.Land
FROM Fahrzeugtyp ft
join Fahrzeughersteller fh on ft.Hersteller_ID = fh.ID;
Für den Anwender sieht es tatsächlich so aus, als hätten wir eine einfache Tabelle mit allen Angaben:
Damit kann das letzte der Beispiele zu OUTER JOIN vereinfacht werden.
Hole alle Dienstwagen (ggf. mit den zugehörigen Mitarbeitern) und nenne dazu alle Fahrzeugdaten.
SELECT
mi.Personalnummer AS MitNr,
mi.Name, mi.Vorname,
dw.ID AS DIW, dw.Kennzeichen, dw.Fahrzeugtyp_ID AS TypID,
fa.Bezeichnung AS Typ, fa.Hersteller
FROM Dienstwagen dw
LEFT JOIN Mitarbeiter mi ON mi.ID = dw.Mitarbeiter_ID
INNER JOIN Fahrzeugart fa ON fa.ID = dw.Fahrzeugtyp_ID;
MITNR NAME VORNAME DIW KENNZEICHEN TYPID TYP HERSTELLER
------- --------- --------- --- ----------- ----- --------------- -------------
80001 Schindler Christina 8 DO-WB 428 14 A160 Mercedes-Benz
90001 Janssen Bernhard 9 DO-WB 429 14 A160 Mercedes-Benz
100001 Grosser Horst 10 DO-WB 4210 14 A160 Mercedes-Benz
110001 Eggert Louis 11 DO-WB 4211 14 A160 Mercedes-Benz
120001 Carlsen Zacharias 12 DO-WB 4212 14 A160 Mercedes-Benz
13 DO-WB 111 16 W211 (E-Klasse) Mercedes-Benz
50002 Braun Christian 14 DO-WB 352 2 Golf Volkswagen
50003 Polovic Frantisek 15 DO-WB 353 3 Passat Volkswagen
50004 Kalman Aydin 16 DO-WB 354 4 Kadett Opel
80002 Aliman Zafer 17 DO-WB 382 2 Golf Volkswagen
80003 Langer Norbert 18 DO-WB 383 3 Passat Volkswagen
80004 Kolic Ivana 19 DO-WB 384 4 Kadett Opel
Einige kleine Änderungen vereinfachen alles: Die Tabelle Fahrzeugtyp wird durch die View Fahrzeugart ersetzt; der JOIN auf Fahrzeughersteller entfällt ersatzlos. Lediglich zur Klarheit ändern wir Tabellen-Alias und Spaltennamen.
Eine View ändern oder löschen
[Bearbeiten]Die Änderung einer VIEW wird unterschiedlich gehandhabt.
- Üblich ist das „normale“ ALTER VIEW.
- Firebird behandelt eine Änderung mit RECREATE als Löschung und anschließende Neuaufnahme.
Die Löschung einer View erfolgt mit dem üblichen Befehl DROP VIEW.
DROP VIEW Deutscher_Fahrzeugtyp;
Hierbei wird nur die View als Objekt in der Datenbank gelöscht. Die Tabellen und Daten in den Tabellen, auf denen die View basiert, werden davon nicht beeinflusst – sie werden nicht gelöscht.
Zusammenfassung
[Bearbeiten]- Views sind Abfragen, die in der Datenbank als Objekt gespeichert werden.
- Views können die Komplexität für den Anwender reduzieren.
- Views können für eine detaillierte Zugriffskontrolle genutzt werden.
- Views werden in Abfragen wie jede Tabelle benutzt.
- Sie werden mit CREATE VIEW erstellt und mit DROP VIEW gelöscht.
Übungen
[Bearbeiten]Die Formulierung „eine View kontrollieren“ meint: Mit einer geeigneten Abfrage soll überprüft werden, ob die View richtig erstellt worden ist.
Übung 1 | Definitionen | Zur Lösung |
Welche der folgenden Feststellungen sind richtig, welche sind falsch?
- Eine View ist wie eine „normale“ Abfrage, deren Bestandteile in der Datenbank fest gespeichert werden.
- Das Ergebnis dieser Abfrage wird gleichzeitig gespeichert und steht damit beim nächsten Aufruf der View sofort zur Verfügung.
- Eine ORDER BY-Klausel kann in einer View immer benutzt werden.
- Eine ORDER BY-Klausel ist in einer View nicht erforderlich.
- Wenn diese Klausel in einer View benutzt wird, hat diese Sortierung Vorrang vor einer ORDER BY-Klausel in dem SELECT-Befehl, der die View benutzt.
- Wenn ein SELECT-Befehl komplexe JOINs oder andere Klauseln benutzt und häufiger benutzt wird, ist es sinnvoll, ihn in einer View zu kapseln.
- Wenn ein Anwender nicht alle Daten sehen darf, ist es notwendig, die Zugriffsrechte auf die Spalten zu beschränken; diese Beschränkung kann nicht über eine View gesteuert werden.
- Eine View kann in einem SELECT-Befehl in der FROM-Klausel anstatt einer Tabelle aufgerufen werden.
- Eine View kann nicht in einem JOIN benutzt werden.
Übung 2 | Eine View benutzen | Zur Lösung |
Skizzieren Sie eine Abfrage, durch die eine beliebige View benutzt werden kann.
Übung 3 | Eine einfache View erstellen | Zur Lösung |
Bei der Suche nach Dienstwagen sollen mit der View Dienstwagen_Anzeige immer auch angezeigt werden:
- Name und Vorname des Mitarbeiters
- ID und Bezeichnung seiner Abteilung
- der Fahrzeugtyp (nur als ID)
Stellen Sie sicher, dass auch nicht-persönliche Dienstwagen immer angezeigt werden, und kontrollieren Sie das Ergebnis durch eine Abfrage ähnlich diesem Muster:
SELECT * FROM Dienstwagen_Anzeige WHERE ( Abt_ID BETWEEN 5 AND 8 ) or ( Mi_Name is null );
Übung 4 | Mehrere Tabellen und Views verbinden | Zur Lösung |
Erweitern Sie die vorstehende View so, dass mit Hilfe der View Fahrzeugart auch Bezeichnung, Hersteller und Land angezeigt werden. Kontrollieren Sie das Ergebnis durch die o. g. Abfrage.
Dies ist ein Beispiel dafür, dass eine View bei Abfragen genauso wie eine „echte“ Tabelle benutzt werden kann.
Übung 5 | Eine VIEW auf mehrere Tabellen | Zur Lösung |
Erstellen Sie eine Sicht Vertrag_Anzeige, bei der zu jedem Vertrag angezeigt werden:
- ID, Vertragsnummer, Abschlussdatum, Art (als Text)
- Name, Vorname des Mitarbeiters
- Name, Vorname des Versicherungsnehmers
- Kennzeichen des Fahrzeugs
Übung 6 | Eine VIEW auf mehrere Tabellen | Zur Lösung |
Erweitern Sie die vorstehende View so, dass mit Hilfe der View Fahrzeugart auch Bezeichnung, Hersteller und Land angezeigt werden.
Übung 7 | Eine View abschnittsweise kontrollieren | Zur Lösung |
Erstellen Sie eine Abfrage, sodass für einen Teil der Verträge die vorstehende View kontrolliert wird.
Übung 8 | Eine weitere VIEW auf mehrere Tabellen | Zur Lösung |
Erstellen Sie eine Sicht Schaden_Anzeige, bei der zu jedem an einem Schadensfall beteiligten Fahrzeug angezeigt werden:
- ID, Datum, Gesamthöhe eines Schadensfalls
- Kennzeichen und Typ des beteiligten Fahrzeugs
- Anteiliger Schaden
- ID des Versicherungsvertrags
Übung 9 | Eine weitere VIEW auf mehrere Tabellen | Zur Lösung |
Erweitern Sie die vorstehende View so, dass mit Hilfe der View Fahrzeugart auch Bezeichnung, Hersteller und Land sowie Vertragsnummer und ID des Versicherungsnehmers angezeigt werden.
Übung 10 | Eine View zur Auswertung einer View | Zur Lösung |
Erstellen Sie eine weitere View so, dass die vorstehende View für alle Schadensfälle des aktuellen Jahres benutzt wird.
Lösung zu Übung 1 | Definitionen | Zur Übung |
Richtig sind die Aussagen 1, 3, 4, 6, 8. Falsch sind die Aussagen 2, 5, 7, 9.
Lösung zu Übung 2 | Eine View benutzen | Zur Übung |
SELECT * FROM <View-Name>;
Lösung zu Übung 3 | Eine View erstellen | Zur Übung |
create view Dienstwagen_Anzeige
( Kennzeichen, TypId,
Mi_Name, Mi_Vorname,
Ab_ID, Ab_Name )
as select dw.Kennzeichen, dw.Fahrzeugtyp_ID,
mi.Name, mi.Vorname,
mi.Abteilung_ID,
ab.Bezeichnung
from Dienstwagen dw
left join Mitarbeiter mi
on mi.ID = dw.Mitarbeiter_ID
left join Abteilung ab
on ab.ID = mi.Abteilung_ID;
Erläuterung: LEFT JOIN in beiden Fällen wird benötigt, damit auch NULL-Werte, nämlich die nicht-persönlichen Dienstwagen angezeigt werden.
Lösung zu Übung 4 | Mehrere Tabellen und Views verbinden | Zur Übung |
alter view Dienstwagen_Anzeige
( Kennzeichen, TypId,
Typ, Fz_Hersteller, Fz_Land,
Mi_Name, Mi_Vorname,
Ab_ID, Ab_Name )
as select dw.Kennzeichen, dw.Fahrzeugtyp_ID,
fa.Bezeichnung, fa.Hersteller, fa.Land,
mi.Name, mi.Vorname,
mi.Abteilung_ID,
ab.Bezeichnung
from Dienstwagen dw
left join Mitarbeiter mi
on mi.ID = dw.Mitarbeiter_ID
left join Abteilung ab
on ab.ID = mi.Abteilung_ID
inner join Fahrzeugart fa
on fa.ID = dw.Fahrzeugtyp_ID;
Lösung zu Übung 5 | Eine VIEW auf mehrere Tabellen | Zur Übung |
create view Vertrag_Anzeige
( ID, Vertragsnummer, Abschlussdatum, Art,
Mi_Name, Mi_Vorname,
Vn_Name, Vn_Vorname,
Kennzeichen )
as select vv.ID, vv.Vertragsnummer, vv.Abschlussdatum,
CASE vv.Art
WHEN 'TK' THEN 'Teilkasko'
WHEN 'VK' THEN 'Vollkasko'
ELSE 'Haftpflicht'
END,
mi.Name, mi.Vorname,
vn.Name, vn.Vorname,
fz.Kennzeichen
from Versicherungsvertrag vv
join Mitarbeiter mi
on mi.ID = vv.Mitarbeiter_ID
join Versicherungsnehmer vn
on vn.ID = vv.Versicherungsnehmer_ID
join Fahrzeug fz
on fz.ID = vv.Fahrzeug_ID;
Hinweis: Weil die Zusatzangaben Pflicht sind, können wir einheitlich mit INNER JOIN arbeiten.
Lösung zu Übung 6 | Eine VIEW auf mehrere Tabellen | Zur Übung |
alter view Vertrag_Anzeige
( ID, Vertragsnummer, Abschlussdatum, Art,
Mi_Name, Mi_Vorname,
Vn_Name, Vn_Vorname,
Kennzeichen, Typ, Hersteller, Land )
as select vv.ID, vv.Vertragsnummer, vv.Abschlussdatum,
CASE vv.Art
WHEN 'TK' THEN 'Teilkasko'
WHEN 'VK' THEN 'Vollkasko'
ELSE 'Haftpflicht'
END,
mi.Name, mi.Vorname,
vn.Name, vn.Vorname,
fz.Kennzeichen, fa.Bezeichnung, fa.Hersteller, fa.Land
from Versicherungsvertrag vv
join Mitarbeiter mi
on mi.ID = vv.Mitarbeiter_ID
join Versicherungsnehmer vn
on vn.ID = vv.Versicherungsnehmer_ID
join Fahrzeug fz
on fz.ID = vv.Fahrzeug_ID
join Fahrzeugart fa
on fa.ID = fz.Fahrzeugtyp_ID;
Lösung zu Übung 7 | Eine View abschnittsweise kontrollieren | Zur Übung |
SELECT * FROM Vertrag_Anzeige
WHERE EXTRACT(YEAR from Abschlussdatum) <= 1990;
Lösung zu Übung 8 | Eine weitere VIEW auf mehrere Tabellen | Zur Übung |
create view Schaden_Anzeige
( ID, Datum, Gesamtschaden,
Kennzeichen, Typ,
Schadensanteil,
VV_ID )
as select sf.ID, sf.Datum, sf.Schadenshoehe,
fz.Kennzeichen, fz.Fahrzeugtyp_ID,
zu.Schadenshoehe,
vv.ID
from Zuordnung_SF_FZ zu
join Schadensfall sf
on sf.ID = zu.Schadensfall_ID
join Fahrzeug fz
on fz.ID = zu.Fahrzeug_ID
join Versicherungsvertrag vv
on fz.ID = vv.Fahrzeug_ID;
Lösung zu Übung 9 | Eine weitere VIEW auf mehrere Tabellen | Zur Übung |
alter view Schaden_Anzeige
( ID, Datum, Gesamtschaden,
Kennzeichen, Typ, Hersteller, Land,
Schadensanteil,
VV_ID, Vertragsnummer, VN_ID )
as select sf.ID, sf.Datum, sf.Schadenshoehe,
fz.Kennzeichen, fa.Bezeichnung, fa.Hersteller, fa.Land,
zu.Schadenshoehe,
vv.ID, vv.Vertragsnummer, vv.Versicherungsnehmer_ID
from Zuordnung_SF_FZ zu
join Schadensfall sf
on sf.ID = zu.Schadensfall_ID
join Fahrzeug fz
on fz.ID = zu.Fahrzeug_ID
join Versicherungsvertrag vv
on fz.ID = vv.Fahrzeug_ID
join Fahrzeugart fa
on fa.ID = fz.Fahrzeugtyp_ID;
Lösung zu Übung 10 | Eine View zur Auswertung einer View | Zur Übung |
create view Schaden_Anzeige_Jahr
as select *
from Schaden_Anzeige
where EXTRACT(YEAR from Datum) = EXTRACT(YEAR from CURRENT_DATE);
Siehe auch
[Bearbeiten]Ergänzende Informationen gibt es in den folgenden Kapiteln: