Skip to Content
2026SOFT | DB-Programmierung (13-15)

SOFT | DB-Programmierung (13-15)

Datum: September 2026
Lesedauer: 18 Minuten

Überarbeitet mit Claude Sonnet 5


Referenzmodul: Softwareprogrammierung (SOFT) - Dipl. Informatiker HF

Quellen:

  • Grundkurs Datenbankentwurf - Eine beispielorientierte Einführung für Studierende und Praktiker (4. Auflage)
    Helmut Jarosch, Springer Vieweg
  • Grundkurs Datenbankentwicklung - Von der Anforderungsanalyse zur komplexen Datenbankanfrage (5. Auflage)
    Stephan Kleuker, Springer Vieweg
  • Grundkurs JAVA - Von den Grundlagen bis zu Datenbank- und Netzanwendungen (12. Auflage)
    Dietmar Abts, Springer Vieweg
  • WISS Schulen für Wirtschaft Informatik Immobilien Unterricht Juni - September 2026

Block 13: Datenbank-Design

Schichten-Architektur einer DB-Anwendung

Der Client greift nie direkt auf das DBMS zu, sondern immer über die Geschäftslogik- und Datenzugriffskomponenten der Mittelschicht. Das erlaubt es, Datenzugriffsdetails, Validierung und Berechtigungen zentral zu kontrollieren.

Arten von Datenbankmanagementsystemen (DBMS)

Geschichtliche Entwicklung

JahrzehntModellGrundprinzip
1960erHierarchisches DBMSDaten als Baumstruktur, jedes Kind hat genau ein Elternelement
1970erNetzwerk-DBMS (CODASYL)Daten als Graph, ein Kind kann mehrere Eltern besitzen
1970erRelationales DBMSDaten als Tabellen, Beziehungen über gemeinsame Werte (relationale Algebra)
1990erObjektorientiertes DBMSdirekte Abbildung von Objekten inklusive Vererbung, ohne Umweg über Tabellen

Heutige Kategorien mit Beispielen

KategorieBeispiel
Relationales DBMSMySQL, PostgreSQL
Objektrelationales DBMSOracle Database
Objektorientiertes DBMSObjectDB
NoSQL-DatenbankMongoDB

ACID-Prinzip

Relationale DBMS garantieren für Transaktionen die ACID-Eigenschaften:

KriteriumBedeutung
Atomicity (Atomarität)Eine Transaktion wird vollständig oder gar nicht ausgeführt.
Consistency (Konsistenz)Die Datenbank bleibt vor und nach der Transaktion in einem gültigen, regelkonformen Zustand.
Isolation (Isolation)Parallele Transaktionen beeinflussen sich nicht gegenseitig; jede wirkt, als liefe sie allein.
Durability (Dauerhaftigkeit)Nach einem erfolgreichen Commit bleiben Änderungen dauerhaft erhalten, auch nach einem Systemabsturz.

Einordnung und Vergleich von DBMS

Vergleichsportale wie DB-Engines bewerten die Verbreitung von DBMS anhand von Kriterien wie Stellenanzeigen, Erwähnungen in Fachartikeln und Suchvolumen. Eine solche Rangliste ist ein Popularitätsindikator, keine technische Qualitätsaussage. Für die Auswahl eines DBMS sind das passende Datenmodell (relational, dokumentenorientiert, Key-Value, spaltenorientiert, graphbasiert), die Konsistenzanforderungen, die Skalierbarkeit, das Ökosystem sowie die Betriebskosten meist aussagekräftiger als eine allgemeine Rangfolge.

NoSQL-Datenbanken

Motivation

NoSQL-Systeme entstanden, weil klassische relationale DBMS bei bestimmten Anforderungen an Grenzen stossen:

  • grössere Schemaflexibilität für unstrukturierte oder halbstrukturierte Daten
  • flexible, häufige Schemaänderungen ohne aufwändige Migration
  • horizontale Skalierbarkeit über viele Server hinweg statt nur vertikale Aufrüstung
  • Umgang mit sehr grossen, dezentral gespeicherten Datenmengen (Big Data)

Merkmale

“NoSQL” steht für “Not only SQL”. Typische Merkmale sind ein nicht-relationales Datenmodell, schwache oder fehlende Schemavorgaben, Fokus auf horizontale statt vertikale Skalierung, oft andere Konsistenzmodelle als ACID (z. B. das BASE-Modell: Basically Available, Soft State, Eventually Consistent) sowie eine für hohe Lese-/Schreiblast statt komplexe Verknüpfungen optimierte Suche.

Typen von NoSQL-Datenbanken

TypGrundprinzipBeispiel
Key-Value-Storeeinfache Schlüssel-Wert-Paare, sehr schneller ZugriffRedis
Dokumentenorientiertspeichert halbstrukturierte Dokumente (JSON/BSON)MongoDB
SpaltenorientiertDaten spaltenweise gespeichert, effizient für Aggregation über riesige DatenmengenCassandra
GraphdatenbankKnoten und Kanten bilden Beziehungen explizit abNeo4j

XML im Datenbankkontext

XML (eXtensible Markup Language) ist eine textbasierte Auszeichnungssprache mit selbst definierten Tags, z. B. <note>Inhalt</note>. Der Standard wird vom World Wide Web Consortium (W3C) gepflegt.

Die zentrale Idee dieser Verarbeitungskette ist die Trennung von Daten und Darstellung: Die Daten liegen einmal im XML-Format vor und lassen sich mit unterschiedlichen XSLT-Stylesheets in verschiedene Ausgabeformate überführen, ohne die Datenbasis zu verändern.

XPath

XPath ist eine Abfragesprache für Positionen innerhalb eines XML-Baums und bildet die Grundlage für XSLT, XPointer und XQuery. Ein Lokationspfad wie /doc/chapter[3]/section wählt den section-Knoten innerhalb des dritten chapter-Elements aus.

Die XPath-Achsen beschreiben, wie ein Knoten im Verhältnis zu anderen Knoten im DOM-Baum liegt:

AchseBedeutung
selfder aktuelle Knoten selbst
parentdirekt übergeordneter Knoten
childdirekt untergeordnete Knoten
ancestoralle übergeordneten Knoten (Eltern, Grosseltern usw.)
descendantalle untergeordneten Knoten (Kinder, Enkel usw.)
preceding-siblingGeschwisterknoten vor dem aktuellen Knoten
following-siblingGeschwisterknoten nach dem aktuellen Knoten
precedingalle Knoten, die im Dokument vor dem aktuellen Knoten liegen
followingalle Knoten, die im Dokument nach dem aktuellen Knoten liegen

XQuery

XQuery ist die Abfragesprache für XML-Daten, vergleichbar mit SQL für relationale Daten. Ein FLWOR-Ausdruck (For, Let, Where, Order by, Return) kombiniert Iteration über Knoten, Zwischenwerte, Filterung, Sortierung und Ergebnisaufbau in einer einzigen Anfrage:

for $book in doc("catalog.xml")/catalog/book let $price := $book/price where $price > 20 order by $price descending return $book/title

Relationales Datenmodell - Grundbegriffe

Begriff (Theorie)SQL-BegriffBedeutung
RelationTabelleMenge von Objekten eines Objekttyps
TupelZeileein konkretes Objekt
AttributSpalteeine Eigenschaft eines Objekts
Wertebereich (domain)DatentypMenge der für ein Attribut zulässigen Werte
Schlüsselkandidat-Attribut mit garantiert eindeutigen Werten
PrimärschlüsselPRIMARY KEYgewählter Schlüsselkandidat zur eindeutigen Identifikation
FremdschlüsselFOREIGN KEYVerweis auf den Primärschlüssel einer anderen Relation

Regeln für eine Relation: keine zwei identischen Tupel, Attributnamen innerhalb einer Relation eindeutig, Attributwerte atomar, Nullwerte sind erlaubt, ausser im Primärschlüssel.

MySQL als Beispiel-DBMS

Der MySQL Community Server läuft als Hintergrunddienst und verwaltet die eigentlichen Daten. Die MySQL Workbench ist ein grafisches Werkzeug, um mit diesem Server zu arbeiten. Eine Connection verbindet die Workbench mit einer konkreten DBMS-Instanz - lokal auf dem eigenen Rechner oder remote auf einem anderen Server. Für Testzwecke wird häufig root/password als Standardzugang verwendet; in produktiven Umgebungen muss dieser zwingend geändert werden. Sakila ist eine mitgelieferte Beispieldatenbank, die sich gut zum Üben eignet.

Eine DBMS-Instanz ist der laufende Serverprozess, der eine oder mehrere Datenbanken verwaltet. Ein Schema beschreibt die Struktur einer einzelnen Datenbank: ihre Tabellen, Sichten (Views), gespeicherten Prozeduren und Funktionen.

Von der Anforderung zum Datenbankschema

AnsatzVorgehenErgebnis
Objektorientierte Analyse (OOA)fachliche Objekte mit Attributen und Verhalten modellierenUML-Klassendiagramm
Strukturierte Analyse (SA)Daten und Funktionen getrennt betrachtensemantisches Entity-Relationship-Modell (ERM nach Chen)
Normalisierungvon einer “flachen” Tabelle ausgehen und schrittweise zerlegen1., 2., 3. Normalform

Das entstehende fachliche Modell wird über ein Entity-Relationship-Diagramm (ERD) und objektrelationales Mapping (ORM) in ein konkretes relationales Schema und schliesslich in SQL umgesetzt.

Integritätsbedingungen

Entitätsintegrität

Ein Primärschlüssel identifiziert jedes Tupel eindeutig und darf niemals NULL sein. Schlüsselkandidaten sind Attribute mit garantiert eindeutigen Werten; üblicherweise wird das kürzeste geeignete Attribut als Primärschlüssel gewählt, z. B. eine Kundennummer. Existiert kein passender natürlicher Kandidat, wird ein künstlicher Schlüssel erzeugt - eine fortlaufende Nummer oder eine GUID (Globally Unique Identifier).

Referenzielle Integrität

Ein Fremdschlüssel verweist auf den Primärschlüssel einer anderen Relation (oder, bei rekursiven Beziehungen, auf ein anderes Tupel derselben Relation). Es gelten folgende Regeln:

  • Ist die Beziehung optional, darf der Fremdschlüssel NULL sein.
  • Ist ein Wert vorhanden, muss ein passendes Tupel in der referenzierten Relation existieren.
  • Ein Fremdschlüssel kann Teil eines zusammengesetzten Primärschlüssels sein (z. B. in einer n:m-Zuordnungstabelle).
  • Eine Relation kann mehrere Fremdschlüssel besitzen.

Das DBMS muss diese Regeln bei kritischen Operationen (Einfügen, Ändern von Schlüsselwerten, Löschen) durchsetzen. Bei einer Verletzung stehen folgende Strategien zur Verfügung:

StrategieWirkung
Zurückweisendie Operation wird abgelehnt, eine Fehlermeldung erscheint
Kaskadierenabhängige Tupel werden automatisch mitgelöscht oder -geändert (Propagierung)
NULL-/Default-Wert setzender Fremdschlüssel wird zurückgesetzt (nur bei optionaler Beziehung möglich)

Entity-Relationship-Diagramm (ERD) und Objektrelationales Mapping

Ein ERD nach Crow’s-Foot-Notation stellt Entitäten als Rechtecke und Beziehungen als Linien mit Kardinalitätssymbolen dar. Werkzeuge wie die MySQL Workbench können aus einer bestehenden Datenbank automatisch ein erweitertes ERD (EERD) erzeugen (Menü Database → Reverse Engineering).

Abbildungsregeln für Klassen und Assoziationen

  • Jede Klasse bzw. Entität wird zu einer eigenen Relation.
  • 1:1-Beziehung: Der Fremdschlüssel entspricht dem Primärschlüssel der referenzierten Tabelle (z. B. eine Filiale hat höchstens eine Leitung, eine Leitung leitet höchstens eine Filiale).
  • 1 (obligatorisch) zu * (optional): Der Fremdschlüssel liegt auf der “Viele”-Seite und darf dort NOT NULL sein, wenn jedes Tupel dieser Seite zwingend zugeordnet sein muss - Beispiel: Jede Mitarbeiterin gehört genau einer Abteilung an, department_id in der Mitarbeitertabelle ist daher NOT NULL.
  • 0..1 (optional) zu 1..* (obligatorisch): Der Fremdschlüssel darf NULL sein, es muss aber mindestens ein Tupel auf der “Viele”-Seite tatsächlich referenzieren.
  • *:* bzw. 1..* zu 1..*: Eine eigene Zuordnungstabelle wird benötigt, die beide Fremdschlüssel als zusammengesetzten Primärschlüssel enthält.

Abbildungsregeln für Generalisierung

VarianteVorgehenBewertung
1: getrennte Relationen für Ober- und Unterklassenje eine Tabelle, verknüpft über eine 1:1-Beziehungsaubere Schlüsselverwaltung, benötigt Joins beim Lesen
2: nur Relationen für die Unterklassengemeinsame Attribute werden in jede Unterklassen-Tabelle dupliziertkein Join nötig, aber redundante Felder in mehreren Tabellen
3: eine gemeinsame Relationein zusätzliches Flag-Attribut je Subtyp (z. B. is_customer, is_supplier)meist beste Performance, aber viele Nullwerte und Redundanz

Normalisierung

Ziel der Normalisierung ist Redundanzfreiheit, ohne dass Informationen verloren gehen. Bei jeder Zerlegung müssen zwei Bedingungen erhalten bleiben:

  • Verbundtreue: Die zerlegten Tabellen lassen sich über einen Join wieder verlustfrei zum ursprünglichen Zustand zusammenführen.
  • Abhängigkeitstreue: Jede fachliche Abhängigkeit bleibt nach der Zerlegung in mindestens einer Teiltabelle abbildbar.

Unzureichende Normalisierung führt zu Anomalien beim Einfügen, Ändern und Löschen von Tupeln: unkontrollierte Redundanz, widersprüchliche Daten und verlorene Informationen.

1. Normalform (1NF)

Jedes Attribut muss einen atomaren Wert enthalten - keine Listen oder Wiederholungsgruppen in einer Zelle.

Verletzt die 1NF (Produkte als Liste in einer Zelle):

Bestellung_NrKundeProdukte
1001MeierTastatur, Maus

In 1NF überführt (ein Produkt pro Zeile):

Bestellung_NrKundeProdukt
1001MeierTastatur
1001MeierMaus

2. Normalform (2NF)

Voraussetzung: 1NF ist erfüllt und der Primärschlüssel besteht aus mehreren Attributen. Jedes Nichtschlüsselattribut muss von der gesamten Schlüsselkombination abhängen, nicht nur von einem Teil davon (keine partielle Abhängigkeit).

Beispiel mit zusammengesetztem Schlüssel (Bestellung_Nr, Produkt_Nr): Das Attribut Kunde hängt nur von Bestellung_Nr ab, nicht vom vollständigen Schlüssel - das verletzt 2NF. Die Lösung trennt die Bestellkopfdaten von den Bestellpositionen:

Bestellung(Bestellung_Nr, Kunde) und Bestellposition(Bestellung_Nr, Produkt_Nr, Menge).

3. Normalform (3NF)

Voraussetzung: 2NF ist erfüllt. Zusätzlich dürfen keine transitiven Abhängigkeiten zwischen Nichtschlüsselattributen bestehen.

Beispiel: In Lieferant(Lieferanten_Nr, Name, PLZ, Ort) hängt Ort unmittelbar von PLZ ab, und PLZ hängt vom Primärschlüssel Lieferanten_Nr ab - Ort ist damit nur transitiv, über PLZ, vom Schlüssel abhängig. Die Lösung trennt die Postleitzahlen aus:

Lieferant(Lieferanten_Nr, Name, PLZ) und Postleitzahl(PLZ, Ort).

Denormalisierung

Weitergehende Normalformen haben in der Praxis meist keine Relevanz. Denormalisierung bedeutet, bewusst wieder Redundanz in Kauf zu nehmen, um die Performance zu verbessern - zum Beispiel, indem Adresselemente wie Strasse und Ort direkt in der Kundentabelle belassen werden, statt sie in eine eigene Tabelle auszulagern.

Block 14: SQL

Teilsprachen von SQL

TeilspracheLangformAufgabe
DDLData Definition LanguageSchemata und Schemaobjekte erzeugen, ändern, löschen (DB-Struktur)
DCLData Control LanguageZugriffsrechte vergeben und entziehen
DMLData Manipulation LanguageTabelleninhalte anlegen, ändern, löschen
DQL / DRLData Query / Retrieval LanguageTabelleninhalte abfragen, relationen- und mengenorientierte Operationen

Geschichtliche Meilensteine

JahrMeilenstein
1970E. F. Codd veröffentlicht das relationale Modell und die relationale Algebra
1979Relational Software (später Oracle) bringt das erste kommerzielle SQL-System
1981IBM veröffentlicht SQL/DS
1983IBM veröffentlicht DB2
1986erste ANSI-Norm für SQL
1999SQL-3 bringt objektrelationale Erweiterungen

DDL: Schema und Tabellen erzeugen

Eine Datenbank lässt sich grafisch über die MySQL Workbench oder programmatisch über DDL-Anweisungen erzeugen und pflegen. In Softwareprojekten steckt DDL häufig in Migrationsskripten, die beim Installieren oder Aktualisieren einer Anwendung automatisch ausgeführt werden.

CREATE DATABASE company; DROP DATABASE company;
CREATE TABLE employee ( employee_id INT PRIMARY KEY AUTO_INCREMENT, first_name VARCHAR(50) NOT NULL, last_name VARCHAR(50) NOT NULL, department_id INT, FOREIGN KEY (department_id) REFERENCES department(department_id) );

Wichtige MySQL-Datentypen

KategorieTypInhalt
LogischTINYINT(1)0 = falsch, 1 = wahr
NumerischINTganzzahliger Wert
NumerischDECIMAL(v,n)exakter Fliesskommawert (v Vorkomma-, n Nachkommastellen)
NumerischDOUBLE(v,n)grosser, nicht exakter Fliesskommawert
Datum/ZeitDATEYYYY-MM-DD
Datum/ZeitTIMEHH:MM:SS
Datum/ZeitDATETIMEYYYY-MM-DD HH:MM:SS
TextVARCHAR(n)Zeichenkette variabler Länge bis n Zeichen
TextTEXTlange Zeichenkette
BinärdatenLONGBLOBBinärdaten bis 4 GB

Tabellen ändern und löschen

ALTER TABLE employee ADD COLUMN hire_date DATE, MODIFY COLUMN last_name VARCHAR(80) NOT NULL, DROP COLUMN department_id; DROP TABLE employee;

Integritätsbedingungen definieren

CREATE TABLE department ( department_id INT PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE ); CREATE TABLE employee ( employee_id INT PRIMARY KEY, department_id INT, FOREIGN KEY (department_id) REFERENCES department(department_id) );

NOT NULL erzwingt einen Wert, UNIQUE erzwingt Eindeutigkeit, PRIMARY KEY kombiniert beides und identifiziert das Tupel, REFERENCES bindet einen Fremdschlüssel an den Primärschlüssel einer anderen Tabelle.

Sichten (Views)

CREATE VIEW active_employees AS SELECT employee_id, first_name, last_name FROM employee WHERE active = TRUE; DROP VIEW active_employees;

Eine View speichert keine eigenen Daten, sondern eine gespeicherte Abfrage, die wie eine Tabelle gelesen werden kann.

Gespeicherte Prozeduren (Stored Procedures)

DELIMITER // CREATE PROCEDURE raise_salary(IN target_id INT, IN percentage DECIMAL(5,2)) BEGIN UPDATE employee SET salary = salary * (1 + percentage / 100) WHERE employee_id = target_id; END // DELIMITER ;

Eine Prozedur bündelt mehrere Anweisungen zu einem wiederverwendbaren, aufrufbaren Programm. Sie ist vor allem bei datenintensiven Verarbeitungen sinnvoll, die möglichst nahe an den Daten laufen sollen.

Funktionen

CREATE FUNCTION full_name(first_name VARCHAR(50), last_name VARCHAR(50)) RETURNS VARCHAR(101) DETERMINISTIC RETURN CONCAT(first_name, ' ', last_name);

Eine Funktion liefert immer genau einen Rückgabewert und kann sowohl innerhalb von Prozeduren als auch direkt im SELECT als berechnete Spalte oder Filterbedingung verwendet werden.

Trigger

CREATE TRIGGER before_employee_insert BEFORE INSERT ON employee FOR EACH ROW SET NEW.hire_date = COALESCE(NEW.hire_date, CURDATE());

Ein Trigger wird automatisch beim Einfügen, Ändern oder Löschen einer Zeile ausgelöst und kann so Geschäftsregeln direkt im DBMS durchsetzen.

DCL - Zugriffskontrolle

GRANT SELECT, INSERT ON company.employee TO 'reporting_user'@'%'; REVOKE INSERT ON company.employee FROM 'reporting_user'@'%';

GRANT vergibt Rechte, REVOKE entzieht sie wieder.

DML - Tabelleninhalte verändern

Einfügen

INSERT INTO employee (first_name, last_name, department_id) VALUES ('Mira', 'Keller', 3); INSERT INTO employee (first_name, last_name) SELECT first_name, last_name FROM applicant WHERE status = 'accepted';

Die zweite Variante übernimmt Zeilen direkt aus dem Ergebnis einer Abfrage.

Ändern

UPDATE employee SET department_id = 5 WHERE last_name = 'Keller';

Löschen

DELETE FROM employee WHERE department_id = 5;

UPDATE und DELETE wirken auf einzelne Zeilen oder ganze Gruppen, je nach WHERE-Bedingung. Ohne WHERE betrifft die Anweisung alle Zeilen der Tabelle - besondere Vorsicht ist hier geboten.

Abfragen (Teaser)

SELECT * FROM employee;

Details zu Abfragen folgen in Block 15.

Basisarchitekturen: Impedance Mismatch und ORM

Objektorientierte Programme arbeiten mit Objekten, Vererbung und Referenzen; relationale Datenbanken arbeiten mit Tabellen, Zeilen und Fremdschlüsseln. Dieser strukturelle Unterschied wird als Impedance Mismatch bezeichnet und ist der Grund, weshalb Object-Relational Mapping (ORM) existiert: Ein Mapping-Provider übersetzt automatisch zwischen Objektgraphen und relationalen Tabellen.

Einbettungsvarianten von SQL

VarianteBeschreibungBeispiel
Embedded SQLSQL steht direkt im Quelltext einer Wirtssprache und wird vorab übersetztSQLJ
DB-Konnektivitäts-APIStandard-API, um SQL aus einer Programmiersprache heraus abzusetzenJDBC, ODBC
OO-Spracherweiterungdeklarative Zuordnung von Klassen zu TabellenJPA
DB-interner ProgrammcodeLogik läuft direkt im DBMSView, Stored Procedure, Function, Trigger

Statisch, dynamisch, Prepared Statement

  • Statisch: Der SQL-Text steht fest und wird zur Laufzeit nicht verändert.
  • Dynamisch: SQL wird zur Laufzeit aus Teilen zusammengesetzt. Werden dabei Benutzereingaben direkt eingefügt, entsteht eine Angriffsfläche für SQL-Injection.
  • Prepared Statement: Die Struktur der Anweisung steht fest, Werte werden über Platzhalter sicher übergeben, z. B. SELECT * FROM user WHERE name LIKE ?.

Client-Architekturen

Fat Client: Der Grossteil der Logik liegt auf dem Client, der direkt auf die Datenbank zugreift.

Thin Client: Die Logik liegt überwiegend im DBMS, meist als Stored Procedures. Der Client zeigt lediglich Ergebnisse an.

Thin Client mit Applikationsserver: Eine zusätzliche Mittelschicht übernimmt die Geschäftslogik, wahlweise mit oder ohne vorgeschalteten Webserver.

JDBC

ODBC (Open Database Connectivity) ist ein herstellerunabhängiger Standard für Datenbankzugriff aus beliebigen Programmiersprachen. JDBC (Java Database Connectivity) ist das Java-Pendant dazu. Ein JDBC-Treiber - für MySQL etwa “Connector/J” - übersetzt die JDBC-Aufrufe in das herstellerspezifische Protokoll des jeweiligen DBMS.

Datenzugriff in Java via JDBC

String url = "jdbc:mysql://localhost:3306/company"; try (Connection connection = DriverManager.getConnection(url, "app_user", "secret"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery( "SELECT employee_id, first_name, last_name FROM employee")) { while (resultSet.next()) { System.out.println(resultSet.getString("first_name")); } }

Die Reihenfolge ist immer dieselbe: Verbindung aufbauen (Connection), Anweisung vorbereiten (Statement oder PreparedStatement), Anweisung ausführen (executeQuery für Abfragen, executeUpdate für Änderungen), Ergebnis zeilenweise mit ResultSet.next() verarbeiten. try-with-resources schliesst ResultSet, Statement und Connection zuverlässig, auch wenn eine Exception auftritt.

Block 15: SQL Query

Relationale Algebra

Die relationale Algebra legt fest, welche mengen- und relationenorientierten Operationen auf Tabellen zulässig sind; sie ist die formale Grundlage von SQL. Eine Relation ist dabei eine endliche Menge von Tupeln.

OperationRelationenalgebraSQL
Projektionπ(spalten)(R)SELECT columns FROM r
Selektionσ(bedingung)(R)SELECT * FROM r WHERE condition
Verbund (Join)R ⋈ SSELECT * FROM r JOIN s ON ...
Umbenennungρ(neuer_name)(R)SELECT column AS alias FROM r
VereinigungR ∪ SSELECT ... UNION SELECT ...
DifferenzR − SSELECT ... EXCEPT SELECT ...
DurchschnittR ∩ SSELECT ... INTERSECT SELECT ...
Kartesisches ProduktR × SSELECT * FROM r, s

Seit MySQL 8.0.31 werden INTERSECT und EXCEPT nativ unterstützt. In älteren Versionen müssen Durchschnitt und Differenz über Subqueries mit IN/EXISTS bzw. NOT IN/NOT EXISTS nachgebildet werden (siehe unten).

Grundgerüst des SELECT-Befehls

SELECT [DISTINCT] column_list FROM table_list [WHERE condition] [GROUP BY grouping_columns] [HAVING aggregate_condition] [ORDER BY sort_columns [ASC|DESC]];

Die logische Auswertungsreihenfolge lautet FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. Das erklärt zum Beispiel, warum WHERE keine Aggregatfunktion verwenden darf - die Gruppierung findet zeitlich erst danach statt -, HAVING dagegen schon.

Projektion, Umbenennung, Bedingungen

Beispielschema für die folgenden Abfragen: product(product_id, name, category, price).

SELECT name, price AS unit_price FROM product AS p WHERE category = 'electronics';

Ein Alias wie p ist ein Korrelationsname für eine Tabelle innerhalb der Anfrage. Er verkürzt qualifizierte Spaltenverweise und ist bei einem Self-Join sogar zwingend nötig, um dieselbe Tabelle zweimal ansprechen zu können.

Bedingungsoperatoren

OperatorBedeutung
=, <>gleich, ungleich
<, <=, >, >=Grössenvergleich
BETWEEN a AND bWert liegt im Bereich [a, b]
LIKE / NOT LIKEMustervergleich; _ steht für ein beliebiges Zeichen, % für beliebig viele Zeichen
IN (...)Wert kommt in der angegebenen Liste vor
IS NULL / IS NOT NULLPrüfung auf Nullwert

Boolesche Verknüpfung erfolgt über AND, OR, XOR und NOT. Da AND stärker bindet als OR, sollten komplexe Bedingungen konsequent geklammert werden, um Fehlinterpretationen zu vermeiden.

WHERE versus HAVING

SELECT * FROM customer WHERE zip_code = '9000'; SELECT customer_id, SUM(amount) AS total FROM order_line GROUP BY customer_id HAVING total > 1000;

WHERE filtert einzelne Zeilen der Quelltabelle(n), bevor gruppiert wird. HAVING filtert dagegen die bereits gebildeten Gruppen anhand eines Aggregatwerts.

Sortierung

SELECT name, price FROM product ORDER BY price DESC, name ASC;

Aggregation

FunktionBedeutung
COUNT(x)Anzahl Zeilen mit einem Wert in Spalte x
COUNT(*)Anzahl Zeilen insgesamt
SUM(x)Summe der Werte
AVG(x)Durchschnitt der Werte
MIN(x)kleinster Wert
MAX(x)grösster Wert
DISTINCTeliminiert Duplikate
SELECT category, COUNT(*) AS number_of_products, AVG(price) AS average_price FROM product GROUP BY category HAVING AVG(price) > 100;

Alle Spalten im SELECT, die nicht Teil von GROUP BY sind, müssen über eine Aggregatfunktion berechnet werden.

Mengenoperationen

Eine Teilmenge wird implizit über WHERE gebildet. Vereinigung, Durchschnitt und Differenz entsprechen den mathematischen Mengenoperationen, angewendet auf zwei Ergebnismengen mit identischer Spaltenstruktur.

Vereinigung (UNION)

SELECT product_id, name, price FROM product WHERE category = 'electronics' UNION SELECT product_id, name, price FROM product WHERE price > 500 ORDER BY name;

UNION entfernt Duplikate automatisch, UNION ALL behält alle Zeilen einschliesslich Duplikaten und ist dadurch schneller.

Durchschnitt (Intersektion) über Subquery

SELECT * FROM product AS p WHERE p.category = 'electronics' AND p.product_id IN ( SELECT product_id FROM product WHERE price > 500 );
SELECT * FROM product AS p WHERE EXISTS ( SELECT 1 FROM order_line AS ol WHERE ol.product_id = p.product_id );

IN prüft, ob ein Wert in der Ergebnismenge der Subquery vorkommt. EXISTS prüft nur, ob überhaupt mindestens eine passende Zeile existiert, unabhängig vom konkreten Wert - das ist bei grossen Ergebnismengen häufig effizienter.

Differenz (Exklusion) über Subquery

SELECT * FROM product AS p WHERE p.category = 'electronics' AND p.product_id NOT IN ( SELECT product_id FROM order_line );

Achtung: NOT IN verhält sich unerwartet, sobald die Subquery einen NULL-Wert liefert - der gesamte Ausdruck liefert dann kein Ergebnis mehr. NOT EXISTS ist deshalb häufig die robustere Wahl:

SELECT * FROM product AS p WHERE NOT EXISTS ( SELECT 1 FROM order_line AS ol WHERE ol.product_id = p.product_id );

Verbundoperationen (Joins)

SELECT o.order_id, p.name, o.quantity FROM order_line AS o JOIN product AS p ON o.product_id = p.product_id;
Join-TypEnthaltene Zeilen
INNER JOINnur Zeilen mit Übereinstimmung auf beiden Seiten
LEFT JOINalle Zeilen der linken Tabelle, rechte Spalten ggf. NULL
RIGHT JOINalle Zeilen der rechten Tabelle, linke Spalten ggf. NULL
FULL JOINalle Zeilen beider Tabellen, fehlende Seite NULL

MySQL kennt kein natives FULL JOIN; es lässt sich über die Vereinigung eines LEFT JOIN und eines RIGHT JOIN nachbilden:

SELECT p.product_id, p.name, o.order_id FROM product AS p LEFT JOIN order_line AS o ON p.product_id = o.product_id UNION SELECT p.product_id, p.name, o.order_id FROM product AS p RIGHT JOIN order_line AS o ON p.product_id = o.product_id;

Mehrere LEFT JOIN-Schritte lassen sich verketten, um über mehrere Tabellen hinweg auch dann Ergebnisse zu erhalten, wenn einzelne Zwischenstufen keine passende Zeile besitzen:

SELECT o.order_id, c.name AS customer, ci.name AS city FROM order_header AS o LEFT JOIN customer AS c ON c.customer_id = o.customer_id LEFT JOIN address AS a ON a.address_id = c.address_id LEFT JOIN city AS ci ON ci.city_id = a.city_id ORDER BY o.order_id;

Verschachtelte Anfragen (Subqueries)

Subquery als Spalte

SELECT p.product_id, p.name, (SELECT COUNT(*) FROM product AS p2 WHERE p2.category = p.category) AS products_in_category FROM product AS p;

Subquery in der WHERE-Klausel

SELECT * FROM product WHERE price = (SELECT MIN(price) FROM product);

Beide Varianten dürfen jeweils nur genau einen Wert zurückgeben. Werden mehrere Werte erwartet, sind stattdessen IN, ANY oder ALL zu verwenden.

CTEs (Common Table Expressions)

WITH category_average AS ( SELECT category, AVG(price) AS average_price FROM product GROUP BY category ) SELECT p.name, p.price, ca.average_price FROM product AS p JOIN category_average AS ca ON ca.category = p.category WHERE p.price > ca.average_price;

Eine CTE erzeugt eine temporäre, benannte Ergebnismenge, die nur innerhalb der unmittelbar folgenden Anweisung sichtbar ist. Sie verbessert die Lesbarkeit und Strukturierung komplexer Anfragen, insbesondere wenn ein Zwischenergebnis mehrfach verwendet wird.