SOFT | DB-Programmierung (13-15)
Datum: September 2026
Lesedauer: 18 Minuten
Überarbeitet mit Claude Sonnet 5
Referenzmodul: Softwareprogrammierung (SOFT) - Dipl. Informatiker HFQuellen:
- 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
| Jahrzehnt | Modell | Grundprinzip |
|---|---|---|
| 1960er | Hierarchisches DBMS | Daten als Baumstruktur, jedes Kind hat genau ein Elternelement |
| 1970er | Netzwerk-DBMS (CODASYL) | Daten als Graph, ein Kind kann mehrere Eltern besitzen |
| 1970er | Relationales DBMS | Daten als Tabellen, Beziehungen über gemeinsame Werte (relationale Algebra) |
| 1990er | Objektorientiertes DBMS | direkte Abbildung von Objekten inklusive Vererbung, ohne Umweg über Tabellen |
Heutige Kategorien mit Beispielen
| Kategorie | Beispiel |
|---|---|
| Relationales DBMS | MySQL, PostgreSQL |
| Objektrelationales DBMS | Oracle Database |
| Objektorientiertes DBMS | ObjectDB |
| NoSQL-Datenbank | MongoDB |
ACID-Prinzip
Relationale DBMS garantieren für Transaktionen die ACID-Eigenschaften:
| Kriterium | Bedeutung |
|---|---|
| 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
| Typ | Grundprinzip | Beispiel |
|---|---|---|
| Key-Value-Store | einfache Schlüssel-Wert-Paare, sehr schneller Zugriff | Redis |
| Dokumentenorientiert | speichert halbstrukturierte Dokumente (JSON/BSON) | MongoDB |
| Spaltenorientiert | Daten spaltenweise gespeichert, effizient für Aggregation über riesige Datenmengen | Cassandra |
| Graphdatenbank | Knoten und Kanten bilden Beziehungen explizit ab | Neo4j |
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:
| Achse | Bedeutung |
|---|---|
self | der aktuelle Knoten selbst |
parent | direkt übergeordneter Knoten |
child | direkt untergeordnete Knoten |
ancestor | alle übergeordneten Knoten (Eltern, Grosseltern usw.) |
descendant | alle untergeordneten Knoten (Kinder, Enkel usw.) |
preceding-sibling | Geschwisterknoten vor dem aktuellen Knoten |
following-sibling | Geschwisterknoten nach dem aktuellen Knoten |
preceding | alle Knoten, die im Dokument vor dem aktuellen Knoten liegen |
following | alle 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/titleRelationales Datenmodell - Grundbegriffe
| Begriff (Theorie) | SQL-Begriff | Bedeutung |
|---|---|---|
| Relation | Tabelle | Menge von Objekten eines Objekttyps |
| Tupel | Zeile | ein konkretes Objekt |
| Attribut | Spalte | eine Eigenschaft eines Objekts |
| Wertebereich (domain) | Datentyp | Menge der für ein Attribut zulässigen Werte |
| Schlüsselkandidat | - | Attribut mit garantiert eindeutigen Werten |
| Primärschlüssel | PRIMARY KEY | gewählter Schlüsselkandidat zur eindeutigen Identifikation |
| Fremdschlüssel | FOREIGN KEY | Verweis 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
| Ansatz | Vorgehen | Ergebnis |
|---|---|---|
| Objektorientierte Analyse (OOA) | fachliche Objekte mit Attributen und Verhalten modellieren | UML-Klassendiagramm |
| Strukturierte Analyse (SA) | Daten und Funktionen getrennt betrachten | semantisches Entity-Relationship-Modell (ERM nach Chen) |
| Normalisierung | von einer “flachen” Tabelle ausgehen und schrittweise zerlegen | 1., 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
NULLsein. - 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:
| Strategie | Wirkung |
|---|---|
| Zurückweisen | die Operation wird abgelehnt, eine Fehlermeldung erscheint |
| Kaskadieren | abhängige Tupel werden automatisch mitgelöscht oder -geändert (Propagierung) |
| NULL-/Default-Wert setzen | der 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 NULLsein, wenn jedes Tupel dieser Seite zwingend zugeordnet sein muss - Beispiel: Jede Mitarbeiterin gehört genau einer Abteilung an,department_idin der Mitarbeitertabelle ist daherNOT NULL. - 0..1 (optional) zu 1..* (obligatorisch): Der Fremdschlüssel darf
NULLsein, 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
| Variante | Vorgehen | Bewertung |
|---|---|---|
| 1: getrennte Relationen für Ober- und Unterklassen | je eine Tabelle, verknüpft über eine 1:1-Beziehung | saubere Schlüsselverwaltung, benötigt Joins beim Lesen |
| 2: nur Relationen für die Unterklassen | gemeinsame Attribute werden in jede Unterklassen-Tabelle dupliziert | kein Join nötig, aber redundante Felder in mehreren Tabellen |
| 3: eine gemeinsame Relation | ein 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_Nr | Kunde | Produkte |
|---|---|---|
| 1001 | Meier | Tastatur, Maus |
In 1NF überführt (ein Produkt pro Zeile):
| Bestellung_Nr | Kunde | Produkt |
|---|---|---|
| 1001 | Meier | Tastatur |
| 1001 | Meier | Maus |
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
| Teilsprache | Langform | Aufgabe |
|---|---|---|
| DDL | Data Definition Language | Schemata und Schemaobjekte erzeugen, ändern, löschen (DB-Struktur) |
| DCL | Data Control Language | Zugriffsrechte vergeben und entziehen |
| DML | Data Manipulation Language | Tabelleninhalte anlegen, ändern, löschen |
| DQL / DRL | Data Query / Retrieval Language | Tabelleninhalte abfragen, relationen- und mengenorientierte Operationen |
Geschichtliche Meilensteine
| Jahr | Meilenstein |
|---|---|
| 1970 | E. F. Codd veröffentlicht das relationale Modell und die relationale Algebra |
| 1979 | Relational Software (später Oracle) bringt das erste kommerzielle SQL-System |
| 1981 | IBM veröffentlicht SQL/DS |
| 1983 | IBM veröffentlicht DB2 |
| 1986 | erste ANSI-Norm für SQL |
| 1999 | SQL-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
| Kategorie | Typ | Inhalt |
|---|---|---|
| Logisch | TINYINT(1) | 0 = falsch, 1 = wahr |
| Numerisch | INT | ganzzahliger Wert |
| Numerisch | DECIMAL(v,n) | exakter Fliesskommawert (v Vorkomma-, n Nachkommastellen) |
| Numerisch | DOUBLE(v,n) | grosser, nicht exakter Fliesskommawert |
| Datum/Zeit | DATE | YYYY-MM-DD |
| Datum/Zeit | TIME | HH:MM:SS |
| Datum/Zeit | DATETIME | YYYY-MM-DD HH:MM:SS |
| Text | VARCHAR(n) | Zeichenkette variabler Länge bis n Zeichen |
| Text | TEXT | lange Zeichenkette |
| Binärdaten | LONGBLOB | Binä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
| Variante | Beschreibung | Beispiel |
|---|---|---|
| Embedded SQL | SQL steht direkt im Quelltext einer Wirtssprache und wird vorab übersetzt | SQLJ |
| DB-Konnektivitäts-API | Standard-API, um SQL aus einer Programmiersprache heraus abzusetzen | JDBC, ODBC |
| OO-Spracherweiterung | deklarative Zuordnung von Klassen zu Tabellen | JPA |
| DB-interner Programmcode | Logik läuft direkt im DBMS | View, 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.
| Operation | Relationenalgebra | SQL |
|---|---|---|
| Projektion | π(spalten)(R) | SELECT columns FROM r |
| Selektion | σ(bedingung)(R) | SELECT * FROM r WHERE condition |
| Verbund (Join) | R ⋈ S | SELECT * FROM r JOIN s ON ... |
| Umbenennung | ρ(neuer_name)(R) | SELECT column AS alias FROM r |
| Vereinigung | R ∪ S | SELECT ... UNION SELECT ... |
| Differenz | R − S | SELECT ... EXCEPT SELECT ... |
| Durchschnitt | R ∩ S | SELECT ... INTERSECT SELECT ... |
| Kartesisches Produkt | R × S | SELECT * 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
| Operator | Bedeutung |
|---|---|
=, <> | gleich, ungleich |
<, <=, >, >= | Grössenvergleich |
BETWEEN a AND b | Wert liegt im Bereich [a, b] |
LIKE / NOT LIKE | Mustervergleich; _ steht für ein beliebiges Zeichen, % für beliebig viele Zeichen |
IN (...) | Wert kommt in der angegebenen Liste vor |
IS NULL / IS NOT NULL | Prü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
| Funktion | Bedeutung |
|---|---|
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 |
DISTINCT | eliminiert 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-Typ | Enthaltene Zeilen |
|---|---|
INNER JOIN | nur Zeilen mit Übereinstimmung auf beiden Seiten |
LEFT JOIN | alle Zeilen der linken Tabelle, rechte Spalten ggf. NULL |
RIGHT JOIN | alle Zeilen der rechten Tabelle, linke Spalten ggf. NULL |
FULL JOIN | alle 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.