Views erstellen
Lerne, wie du mit Views komplexe Abfragen als virtuelle Tabellen speicherst - für Wiederverwendbarkeit und Übersichtlichkeit.
Stell dir vor, du hast eine komplexe Abfrage mit mehreren JOINs, die du immer wieder brauchst. Anstatt sie jedes Mal neu zu schreiben, kannst du sie als View (Sicht) speichern. Ein View ist wie eine virtuelle Tabelle, die auf einer Abfrage basiert.
Was ist ein View?
Ein View ist eine gespeicherte Abfrage, die wie eine Tabelle verwendet werden kann:
-- View erstellen
CREATE VIEW kunden_uebersicht AS
SELECT
k.id,
k.name,
k.stadt,
COUNT(b.id) AS anzahl_bestellungen,
COALESCE(SUM(b.betrag), 0) AS gesamtumsatz
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.id, k.name, k.stadt;
-- View wie eine Tabelle verwenden
SELECT * FROM kunden_uebersicht;
Ergebnis:
id | name | stadt | anzahl_bestellungen | gesamtumsatz
---+---------------+----------+---------------------+-------------
1 | Anna Schmidt | Berlin | 2 | 199.97
2 | Max Mueller | Hamburg | 1 | 94.98
3 | Lisa Weber | Muenchen | 1 | 19.99
4 | Tom Becker | Berlin | 1 | 184.97
5 | Sarah Klein | Koeln | 0 | 0.00
Grundsyntax
CREATE VIEW view_name AS
SELECT ...;
View erstellen
-- Produkt-Report als View
CREATE VIEW produkt_report AS
SELECT
p.id,
p.name,
p.preis,
p.kategorie,
p.lagerbestand,
p.preis * p.lagerbestand AS lagerwert,
COALESCE(SUM(bp.menge), 0) AS verkauft,
CASE
WHEN p.lagerbestand < 25 THEN 'Nachbestellen'
WHEN p.lagerbestand < 50 THEN 'OK'
ELSE 'Gut bevorratet'
END AS lager_status
FROM produkte p
LEFT JOIN bestellpositionen bp ON p.id = bp.produkt_id
GROUP BY p.id, p.name, p.preis, p.kategorie, p.lagerbestand;
View verwenden
-- Einfache Abfrage auf den View
SELECT * FROM produkt_report;
-- Mit Filter
SELECT name, preis, lager_status
FROM produkt_report
WHERE lager_status = 'Nachbestellen';
-- Mit Sortierung
SELECT name, verkauft
FROM produkt_report
ORDER BY verkauft DESC;
Vorteile von Views
1. Vereinfachung komplexer Abfragen
-- Ohne View: Jedes Mal die komplexe Abfrage schreiben
SELECT k.name, COUNT(b.id) AS bestellungen, SUM(b.betrag) AS umsatz
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.name;
-- Mit View: Einmal definieren, immer wieder nutzen
SELECT name, anzahl_bestellungen, gesamtumsatz
FROM kunden_uebersicht;
2. Sicherheit - Zugriff einschraenken
-- View, der sensible Daten versteckt
CREATE VIEW kunden_public AS
SELECT id, name, stadt
FROM kunden;
-- E-Mail und andere sensible Daten sind nicht sichtbar
-- Mitarbeiter der Marketingabteilung sehen nur den View
SELECT * FROM kunden_public;
3. Konsistente Geschaeftslogik
-- Die "aktive Kunden"-Definition an einem Ort
CREATE VIEW aktive_kunden AS
SELECT k.*
FROM kunden k
WHERE EXISTS (
SELECT 1 FROM bestellungen b
WHERE b.kunden_id = k.id
AND b.bestelldatum >= CURRENT_DATE - INTERVAL '365 days'
);
-- Ueberall im Team die gleiche Definition verwenden
SELECT COUNT(*) FROM aktive_kunden;
Views aendern und loeschen
View ueberschreiben
-- CREATE OR REPLACE: View aktualisieren (PostgreSQL)
CREATE OR REPLACE VIEW kunden_uebersicht AS
SELECT
k.id,
k.name,
k.email,
k.stadt,
COUNT(b.id) AS anzahl_bestellungen,
COALESCE(SUM(b.betrag), 0) AS gesamtumsatz,
MAX(b.bestelldatum) AS letzte_bestellung
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.id, k.name, k.email, k.stadt;
View loeschen
DROP VIEW kunden_uebersicht;
-- Sicherer:
DROP VIEW IF EXISTS kunden_uebersicht;
Views auf Views
Du kannst Views auf anderen Views aufbauen:
-- Basis-View: Alle Kundendaten
CREATE VIEW v_kunden_basis AS
SELECT
k.id,
k.name,
k.stadt,
COUNT(b.id) AS bestellungen,
COALESCE(SUM(b.betrag), 0) AS umsatz
FROM kunden k
LEFT JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.id, k.name, k.stadt;
-- Aufbauender View: Nur Top-Kunden
CREATE VIEW v_top_kunden AS
SELECT *
FROM v_kunden_basis
WHERE umsatz > 100;
-- Verwenden
SELECT * FROM v_top_kunden;
Materialized Views (PostgreSQL)
Normale Views berechnen die Abfrage bei jedem Aufruf neu. Materialized Views speichern das Ergebnis und sind daher schneller:
-- PostgreSQL: Materialized View erstellen
CREATE MATERIALIZED VIEW mv_umsatz_report AS
SELECT
k.name,
k.stadt,
COUNT(b.id) AS bestellungen,
SUM(b.betrag) AS umsatz
FROM kunden k
JOIN bestellungen b ON k.id = b.kunden_id
GROUP BY k.name, k.stadt;
-- Verwenden (sehr schnell, da vorberechnet)
SELECT * FROM mv_umsatz_report;
-- Daten aktualisieren (wenn sich die Quelldaten geaendert haben)
REFRESH MATERIALIZED VIEW mv_umsatz_report;
Vergleich: View vs. Materialized View
| View | Materialized View | |
|---|---|---|
| Daten | Immer aktuell | Snapshot (muss refreshed werden) |
| Geschwindigkeit | Berechnet bei jedem Aufruf | Vorberechnet (schnell) |
| Speicher | Kein extra Speicher | Braucht Speicherplatz |
| Aktualisierung | Automatisch | Manuell (REFRESH) |
| Verfuegbar in | Alle DBs | PostgreSQL, Oracle |
Praxisbeispiele
Dashboard-View
CREATE VIEW dashboard AS
SELECT
(SELECT COUNT(*) FROM kunden) AS kunden_gesamt,
(SELECT COUNT(*) FROM bestellungen WHERE status = 'offen') AS offene_bestellungen,
(SELECT COUNT(*) FROM bestellungen WHERE status = 'versendet') AS versendete_bestellungen,
(SELECT ROUND(SUM(betrag), 2) FROM bestellungen) AS gesamtumsatz,
(SELECT ROUND(AVG(betrag), 2) FROM bestellungen) AS durchschnittlicher_bestellwert;
SELECT * FROM dashboard;
Bestelldetails-View
CREATE VIEW bestelldetails AS
SELECT
b.id AS bestell_nr,
k.name AS kunde,
k.stadt,
b.bestelldatum,
b.status,
p.name AS produkt,
p.kategorie,
bp.menge,
bp.einzelpreis,
bp.menge * bp.einzelpreis AS position_total
FROM bestellungen b
JOIN kunden k ON b.kunden_id = k.id
JOIN bestellpositionen bp ON b.id = bp.bestell_id
JOIN produkte p ON bp.produkt_id = p.id;
-- Jetzt einfach nutzbar:
SELECT * FROM bestelldetails WHERE kunde = 'Anna Schmidt';
SELECT kunde, SUM(position_total) FROM bestelldetails GROUP BY kunde;
Monatlicher Umsatzreport
CREATE VIEW monatlicher_umsatz AS
SELECT
EXTRACT(YEAR FROM bestelldatum) AS jahr,
EXTRACT(MONTH FROM bestelldatum) AS monat,
COUNT(*) AS anzahl_bestellungen,
SUM(betrag) AS umsatz,
ROUND(AVG(betrag), 2) AS avg_bestellwert
FROM bestellungen
GROUP BY EXTRACT(YEAR FROM bestelldatum), EXTRACT(MONTH FROM bestelldatum);
SELECT * FROM monatlicher_umsatz ORDER BY jahr, monat;
Updatable Views
In manchen Faellen kannst du ueber einen View auch Daten aendern:
-- Einfacher View (updatable)
CREATE VIEW berliner_kunden AS
SELECT * FROM kunden WHERE stadt = 'Berlin';
-- Update ueber den View
UPDATE berliner_kunden SET name = 'Anna M.' WHERE id = 1;
-- INSERT ueber den View
INSERT INTO berliner_kunden (id, name, email, stadt)
VALUES (20, 'Neuer Berliner', 'neu@berlin.com', 'Berlin');
Einschraenkung: Views mit JOINs, GROUP BY, DISTINCT oder Aggregatfunktionen sind in der Regel nicht updatable.
Was kommt als Naechstes?
Im naechsten Tutorial lernst du Indizes kennen - damit machst du deine Abfragen deutlich schneller.
Zusammenfassung
- Views speichern komplexe Abfragen als virtuelle Tabellen
- Views werden mit CREATE VIEW … AS SELECT erstellt
- Views vereinfachen Abfragen, schuetzen Daten und sorgen fuer Konsistenz
- Materialized Views (PostgreSQL) speichern Ergebnisse fuer bessere Performance
- Views koennen auf anderen Views aufbauen
- Einfache Views sind teilweise updatable
- Views loescht man mit DROP VIEW
Uebungen
- Einfach: Erstelle einen View
v_teure_produkte, der alle Produkte ueber 50 Euro zeigt. - JOINs: Erstelle einen View
v_bestelluebersicht, der Bestellnummer, Kundenname, Datum und Betrag zeigt. - Aggregation: Erstelle einen View
v_kategorie_stats, der fuer jede Kategorie die Anzahl, den Durchschnittspreis und den Gesamtlagerwert zeigt. - Sicherheit: Erstelle einen View, der Kundendaten ohne E-Mail-Adressen zeigt.
- Dashboard: Erstelle einen View, der die wichtigsten Kennzahlen deines Shops auf einen Blick zeigt.
-- Loesung zu Uebung 1:
CREATE VIEW v_teure_produkte AS
SELECT name, preis, kategorie
FROM produkte
WHERE preis > 50;
-- Loesung zu Uebung 2:
CREATE VIEW v_bestelluebersicht AS
SELECT b.id AS bestell_nr, k.name AS kunde, b.bestelldatum, b.betrag, b.status
FROM bestellungen b
JOIN kunden k ON b.kunden_id = k.id;
Pro-Tipp: Bennene Views mit einem Praefix wie v_ oder vw_, damit du sofort erkennst, ob du eine echte Tabelle oder einen View abfragst. In grossen Projekten hilft das enorm bei der Uebersichtlichkeit. Materialized Views kannst du mit mv_ kennzeichnen.