14 Bedingungslogik

In vielen Situationen möchten wir Daten basierend auf bestimmten Bedingungen transformieren oder auswerten. SQL bietet dafür den CASE-Ausdruck, der es uns ermöglicht, unterschiedliche Werte zurückzugeben, je nachdem, ob eine Bedingung erfüllt ist oder nicht.

14.1 Warum ein CASE?

CASE-Ausdrücke erlauben es uns, Bedingungen zu prüfen und basierend auf den Ergebnissen unterschiedliche Werte zurückzugeben. Dies ist besonders nützlich für:

-- Einfaches Beispiel: Status in lesbare Form bringen
SELECT 
    bestellnummer,
    status,
    CASE status
        WHEN 'N' THEN 'Neu'
        WHEN 'B' THEN 'Bearbeitung'
        WHEN 'V' THEN 'Versendet'
        ELSE 'Unbekannt'
    END AS status_text
FROM bestellungen;

-- Beispiel: Kategorisierung von Zahlen
SELECT 
    produkt_id,
    lagerbestand,
    CASE 
        WHEN lagerbestand = 0 THEN 'Nicht verfügbar'
        WHEN lagerbestand < 10 THEN 'Fast ausverkauft'
        WHEN lagerbestand < 50 THEN 'Verfügbar'
        ELSE 'Gut verfügbar'
    END AS verfuegbarkeit
FROM produkte;

Im ersten Beispiel wird der Bestellstatus, der in der Tabelle als einzelner Buchstabe gespeichert ist, in einen lesbaren Text umgewandelt. Der CASE-Ausdruck prüft den Wert des status und gibt den entsprechenden Text zurück.

Das zweite Beispiel zeigt, wie man Zahlen in Kategorien einteilen kann. Hier wird der Lagerbestand eines Produkts geprüft und je nach Menge eine entsprechende Verfügbarkeitsbeschreibung zurückgegeben.

14.2 Einfacher CASE

Der einfache CASE-Ausdruck vergleicht einen Ausdruck mit einer Reihe von möglichen Werten. Die Syntax sieht folgendermaßen aus:

-- Grundstruktur
CASE ausdruck
    WHEN wert1 THEN ergebnis1
    WHEN wert2 THEN ergebnis2
    [ELSE ergebnis3]
END

Der ausdruck wird nacheinander mit den angegebenen Werten verglichen. Wenn eine Übereinstimmung gefunden wird, wird das entsprechende Ergebnis zurückgegeben. Wenn keine Übereinstimmung gefunden wird und ein ELSE-Zweig angegeben ist, wird dessen Ergebnis zurückgegeben. Ohne ELSE wird NULL zurückgegeben.

-- Praktisches Beispiel: Monatsnamen
SELECT 
    bestelldatum,
    CASE MONTH(bestelldatum)
        WHEN 1 THEN 'Januar'
        WHEN 2 THEN 'Februar'
        WHEN 3 THEN 'März'
        -- ... weitere Monate
        WHEN 12 THEN 'Dezember'
        ELSE 'Ungültig'
    END AS monatsname
FROM bestellungen;

-- Beispiel: Bewertungen umwandeln
SELECT 
    produkt_id,
    bewertung,
    CASE bewertung
        WHEN 1 THEN '★☆☆☆☆'
        WHEN 2 THEN '★★☆☆☆'
        WHEN 3 THEN '★★★☆☆'
        WHEN 4 THEN '★★★★☆'
        WHEN 5 THEN '★★★★★'
        ELSE 'Keine Bewertung'
    END AS bewertung_sterne
FROM produktbewertungen;

Im ersten Beispiel wird aus dem Bestelldatum der Monatsname ermittelt. Dazu wird mit der MONTH-Funktion die Monatsnummer extrahiert und im CASE-Ausdruck mit den möglichen Werten verglichen.

Das zweite Beispiel zeigt, wie man numerische Bewertungen in eine visuelle Darstellung mit Sternen umwandeln kann. Der CASE-Ausdruck ordnet jeder Bewertungszahl die entsprechende Anzahl von Sternen zu.

14.3 Searched CASE

Der Searched CASE ermöglicht es, komplexere Bedingungen zu formulieren. Anstatt einen Ausdruck mit Werten zu vergleichen, können hier beliebige Bedingungen geprüft werden. Die Syntax sieht folgendermaßen aus:

-- Grundstruktur
CASE
    WHEN bedingung1 THEN ergebnis1
    WHEN bedingung2 THEN ergebnis2
    [ELSE ergebnis3]
END

Die Bedingungen werden in der angegebenen Reihenfolge geprüft. Die erste Bedingung, die zutrifft, bestimmt das zurückgegebene Ergebnis. Wenn keine Bedingung zutrifft und ein ELSE-Zweig angegeben ist, wird dessen Ergebnis zurückgegeben. Ohne ELSE wird NULL zurückgegeben.

-- Beispiel: Gehaltsklassen
SELECT 
    name,
    gehalt,
    CASE 
        WHEN gehalt < 30000 THEN 'Niedrig'
        WHEN gehalt < 50000 THEN 'Mittel'
        WHEN gehalt < 80000 THEN 'Hoch'
        ELSE 'Sehr hoch'
    END AS gehaltsklasse
FROM mitarbeiter;

-- Beispiel: Altersgruppen mit überlappenden Bedingungen
SELECT 
    name,
    geburtsdatum,
    CASE 
        WHEN alter < 18 THEN 'Minderjährig'
        WHEN alter BETWEEN 18 AND 25 THEN 'Junge Erwachsene'
        WHEN alter BETWEEN 26 AND 65 THEN 'Erwachsene'
        WHEN alter > 65 THEN 'Senioren'
        ELSE 'Unbekannt'
    END AS altersgruppe
FROM kunden;

-- Beispiel: Komplexe Bedingungen
SELECT 
    bestellnummer,
    betrag,
    lieferstatus,
    zahlungsstatus,
    CASE 
        WHEN lieferstatus = 'geliefert' 
          AND zahlungsstatus = 'bezahlt' 
        THEN 'Abgeschlossen'
        WHEN lieferstatus = 'geliefert' 
          AND zahlungsstatus = 'offen' 
        THEN 'Zahlung ausstehend'
        WHEN lieferstatus IN ('neu', 'in Bearbeitung') 
          AND zahlungsstatus = 'bezahlt' 
        THEN 'Lieferung ausstehend'
        ELSE 'In Bearbeitung'
    END AS bestellstatus
FROM bestellungen;

Im ersten Beispiel werden Mitarbeiter anhand ihres Gehalts in verschiedene Gehaltsklassen eingeteilt. Die Bedingungen prüfen das Gehalt und geben die entsprechende Klasse zurück.

Das zweite Beispiel zeigt, wie man überlappende Bedingungen formulieren kann. Hier werden Kunden anhand ihres Alters in verschiedene Altersgruppen eingeteilt. Die Bedingungen sind so formuliert, dass jeder Kunde genau einer Gruppe zugeordnet wird.

Im dritten Beispiel werden komplexe Bedingungen verwendet, um den Status einer Bestellung zu ermitteln. Hier werden mehrere Spalten (lieferstatus und zahlungsstatus) in den Bedingungen kombiniert, um den entsprechenden Bestellstatus zu bestimmen.

Praktische Anwendungsbeispiele zeigen, wie CASE-Ausdrücke in verschiedenen Situationen eingesetzt werden können:

  1. Berechnungen basierend auf Bedingungen:
SELECT 
    produkt_id,
    preis,
    CASE 
        WHEN kategorie = 'Premium' THEN preis * 0.9
        WHEN kategorie = 'Standard' THEN preis * 0.95
        ELSE preis
    END AS rabattierter_preis
FROM produkte;

Hier wird der Preis eines Produkts basierend auf seiner Kategorie rabattiert. Für Produkte der Kategorie ‘Premium’ wird ein Rabatt von 10% gewährt, für ‘Standard’-Produkte 5%. Alle anderen Produkte bleiben unverändert.

  1. Formatierung von Ausgaben:
SELECT 
    name,
    CASE 
        WHEN telefon IS NULL AND mobil IS NOT NULL 
        THEN CONCAT('Mobil: ', mobil)
        WHEN telefon IS NOT NULL AND mobil IS NULL 
        THEN CONCAT('Tel: ', telefon)
        WHEN telefon IS NOT NULL AND mobil IS NOT NULL 
        THEN CONCAT('Tel: ', telefon, ', Mobil: ', mobil)
        ELSE 'Keine Nummer'
    END AS kontakt
FROM kunden;

In diesem Beispiel wird die Kontaktinformation eines Kunden formatiert. Je nachdem, ob Telefon- und/oder Mobilnummer vorhanden sind, wird eine entsprechende Ausgabe generiert.

  1. Gruppierung und Aggregation:
SELECT 
    CASE 
        WHEN land IN ('DE', 'AT', 'CH') THEN 'DACH'
        WHEN land IN ('FR', 'IT', 'ES') THEN 'Südeuropa'
        ELSE 'Andere'
    END AS region,
    COUNT(*) as anzahl,
    AVG(umsatz) as durchschnittsumsatz
FROM kunden
GROUP BY 
    CASE 
        WHEN land IN ('DE', 'AT', 'CH') THEN 'DACH'
        WHEN land IN ('FR', 'IT', 'ES') THEN 'Südeuropa'
        ELSE 'Andere'
    END;

Hier werden Kunden anhand ihres Landes in Regionen eingeteilt. Für jede Region werden dann die Anzahl der Kunden und der durchschnittliche Umsatz berechnet. Der CASE-Ausdruck wird sowohl in der SELECT-Liste als auch in der GROUP BY-Klausel verwendet, um die Gruppierung nach den definierten Regionen durchzuführen.

  1. UPDATE mit CASE:
UPDATE produkte
SET rabatt = 
    CASE 
        WHEN lagerbestand > 100 THEN 20
        WHEN lagerbestand > 50 THEN 10
        WHEN lagerbestand > 20 THEN 5
        ELSE 0
    END;

Dieses Beispiel zeigt, wie man mit einem CASE-Ausdruck Werte in einer Tabelle aktualisieren kann. Hier wird der Rabatt für Produkte basierend auf ihrem Lagerbestand festgelegt. Produkte mit hohem Lagerbestand erhalten einen höheren Rabatt als Produkte mit niedrigem Bestand.

Tipps zur Optimierung und Behandlung von NULL-Werten runden das Thema ab:

  1. Performance optimieren:
-- Index für häufig verwendete Bedingungen
CREATE INDEX idx_status_betrag 
ON bestellungen(status, betrag);

-- Komplexe CASE-Ausdrücke in View auslagern
CREATE VIEW bestellstatus AS
SELECT 
    bestellnummer,
    CASE 
        WHEN status = 'N' AND betrag > 1000 THEN 'Wichtig'
        WHEN status = 'N' THEN 'Normal'
        ELSE 'Abgeschlossen'
    END AS prioritaet
FROM bestellungen;

Um die Performanz von Abfragen mit CASE-Ausdrücken zu verbessern, können Indizes für häufig verwendete Bedingungen erstellt werden. Dadurch kann die Datenbank die relevanten Datensätze schneller finden.

Eine weitere Möglichkeit ist es, komplexe CASE-Ausdrücke in eine Sicht (View) auszulagern. Dadurch muss der Ausdruck nicht bei jeder Abfrage neu ausgewertet werden, sondern kann einfach über die Sicht abgefragt werden.

  1. NULL-Werte beachten:
-- NULL-Werte explizit behandeln
SELECT 
    name,
    CASE 
        WHEN email IS NULL THEN 'Keine E-Mail'
        ELSE email
    END AS kontakt
FROM kunden;

Bei der Arbeit mit CASE-Ausdrücken ist es wichtig, NULL-Werte zu berücksichtigen. In diesem Beispiel wird geprüft, ob die E-Mail-Adresse eines Kunden NULL ist. Wenn ja, wird stattdessen der Text ‘Keine E-Mail’ zurückgegeben.

  1. Wartbarkeit verbessern:
-- Kommentare für komplexe Bedingungen
SELECT 
    auftragsnummer,
    CASE 
        -- Eilaufträge
        WHEN prioritaet = 1 AND lieferzeit < 24 THEN 'Express'
        -- Standardaufträge
        WHEN prioritaet = 2 THEN 'Standard'
        -- Alle anderen
        ELSE 'Normal'
    END AS auftragstyp
FROM auftraege;

Gerade bei komplexen Bedingungen kann es hilfreich sein, Kommentare im SQL-Code zu verwenden. Dadurch wird die Logik des CASE-Ausdrucks klarer und der Code ist leichter zu warten.

CASE-Ausdrücke sind ein mächtiges Werkzeug, um Daten basierend auf Bedingungen zu transformieren und auszuwerten. Sie ermöglichen es, SQL-Abfragen flexibler und aussagekräftiger zu gestalten und die Ergebnisse an spezifische Anforderungen anzupassen.

Bei der Verwendung von CASE-Ausdrücken sollte man jedoch auch die Performanz im Auge behalten. Komplexe Bedingungen können die Ausführungszeit einer Abfrage erhöhen. Durch den gezielten Einsatz von Indizes und das Auslagern komplexer Ausdrücke in Sichten kann man die Performanz oft verbessern.

Auch die Behandlung von NULL-Werten ist ein wichtiger Aspekt bei der Arbeit mit CASE-Ausdrücken. Durch die explizite Prüfung auf NULL-Werte kann man sicherstellen,