SQL (Structured Query Language) ist die Standardsprache für die Interaktion mit relationalen Datenbanken. Sie wird verwendet, um Daten in Datenbanken zu definieren, zu verwalten und abzurufen. Mit SQL kannst du folgende Operationen ausführen:
SQL-Befehle werden in drei Hauptkategorien unterteilt:
DDL (Data Definition Language) — Sprache zur Definition von Daten:
DML (Data Manipulation Language) — Sprache zur Manipulation von Daten:
DCL (Data Control Language) — Sprache zur Steuerung des Zugriffs:
MySQL 8.1CREATE TABLE students ( student_id INT PRIMARY KEY, name VARCHAR(100), age INT );
MySQL 8.1CREATE TABLE enrollments ( enrollment_id INT PRIMARY KEY, student_id INT, course_id INT, FOREIGN KEY (student_id) REFERENCES students(student_id), FOREIGN KEY (course_id) REFERENCES courses(course_id) );
Normalisierung ist der Prozess, die Struktur einer Datenbank so zu organisieren, dass Datenredundanz reduziert und die Datenintegrität sichergestellt wird.
Vor der Normalisierung:
Nach der Normalisierung:
Tabelle Students
Tabelle Courses
Tabelle Enrollments
JOIN ist eine Operation in SQL, mit der du Zeilen aus zwei oder mehr Tabellen anhand verknüpfter Spalten zusammenführen kannst.
INNER JOIN:
Gibt Datensätze zurück, für die in beiden Tabellen passende Einträge existieren.
LEFT JOIN (oder LEFT OUTER JOIN):
Gibt alle Datensätze aus der linken Tabelle und die passenden Datensätze aus der rechten Tabelle zurück. Gibt es keine Entsprechung, wird NULL für die rechte Tabelle zurückgegeben.
RIGHT JOIN (oder RIGHT OUTER JOIN):
Gibt alle Datensätze aus der rechten Tabelle und die passenden Datensätze aus der linken Tabelle zurück. Gibt es keine Entsprechung, wird NULL für die linke Tabelle zurückgegeben.
FULL OUTER JOIN:
Gibt alle Datensätze zurück, sobald es in einer der Tabellen eine Entsprechung gibt.
CROSS JOIN:
Bildet das kartesische Produkt zweier Tabellen, indem jede Zeile der ersten Tabelle mit jeder Zeile der zweiten Tabelle kombiniert wird.
Ein Subquery ist eine SQL-Abfrage, die innerhalb einer anderen Abfrage verschachtelt ist. Er wird verwendet, um Operationen auszuführen, deren Ergebnis die übergeordnete Abfrage benötigt.
MySQL 8.1SELECT name FROM employees WHERE department_id = (SELECT id FROM departments WHERE name = 'IT');
MySQL 8.1SELECT sub.department, COUNT(*) FROM ( SELECT department_id AS department FROM employees ) sub GROUP BY sub.department;
Verwende das Schlüsselwort DISTINCT im SELECT-Statement, um nur eindeutige Datensätze zurückzugeben.
Beispiel:
MySQL 8.1SELECT DISTINCT position FROM employees;
Beispiel:
MySQL 8.1SELECT department_id, COUNT(*) FROM employees WHERE salary > 50000 GROUP BY department_id;
Beispiel:
MySQL 8.1SELECT department_id, COUNT(*) AS num_employees FROM employees GROUP BY department_id HAVING COUNT(*) > 5;
Ein Index ist eine spezielle Datenstruktur, die das Lesen von Daten aus einer Tabelle beschleunigt, indem sie Verweise auf die Daten anlegt.
Indizes beschleunigen Leseoperationen, können aber Schreiboperationen (Insert, Update, Delete) verlangsamen, da die Indizes bei jeder Datenänderung mit aktualisiert werden müssen.
MySQL 8.1-- Index auf der Spalte name in der Tabelle employees anlegen CREATE INDEX idx_employees_name ON employees(name);
Beispiel:
MySQL 8.1DELETE FROM employees WHERE salary < 30000;
Beispiel:
MySQL 8.1TRUNCATE TABLE employees;
Eine Transaktion ist eine Folge von Operationen, die als eine logische Einheit ausgeführt werden — entweder vollständig oder gar nicht.
Atomarität (Atomicity):
Konsistenz (Consistency):
Isolation (Isolation):
Dauerhaftigkeit (Durability):
Ein Trigger ist eine gespeicherte Prozedur, die automatisch ausgeführt wird, sobald ein bestimmtes Ereignis in der Datenbank eintritt — etwa INSERT, UPDATE oder DELETE auf einer bestimmten Tabelle.
MySQL 8.1CREATE TRIGGER trg_after_insert_employee AFTER INSERT ON employees FOR EACH ROW BEGIN INSERT INTO audit_log (employee_id, action, action_time) VALUES (NEW.id, 'INSERT', NOW()); END;
Ein VIEW (Sicht) ist eine virtuelle Tabelle, die auf dem Ergebnis einer SQL-Abfrage basiert. Ein View speichert selbst keine Daten, sondern stellt eine bestimmte Sicht auf die Daten einer oder mehrerer Tabellen bereit.
MySQL 8.1CREATE VIEW employee_details AS SELECT e.id, e.name, d.name AS department, e.salary FROM employees e JOIN departments d ON e.department_id = d.id;
MySQL 8.1SELECT * FROM employee_details WHERE salary > 50000;
Der LIKE-Operator wird in WHERE-Bedingungen verwendet, um Strings zu finden, die einem bestimmten Muster entsprechen. In den Mustern kommen Platzhalter zum Einsatz:
MySQL 8.1SELECT * FROM employees WHERE name LIKE 'A%';
MySQL 8.1SELECT * FROM employees WHERE name LIKE '%e';
MySQL 8.1SELECT * FROM employees WHERE name LIKE '_a%';
Aggregatfunktionen führen Berechnungen über eine Menge von Werten aus und geben einen einzelnen Wert zurück. Sie werden oft in Kombination mit GROUP BY verwendet.
MySQL 8.1SELECT COUNT(*) FROM employees;
MySQL 8.1SELECT department_id, AVG(salary) AS average_salary FROM employees GROUP BY department_id;
MySQL 8.1SELECT MAX(salary) FROM employees;
MySQL 8.1SELECT SUM(amount) FROM sales WHERE sale_date BETWEEN '2023-01-01' AND '2023-01-31';
Syntax
MySQL 8.1SELECT column_list FROM table1 UNION SELECT column_list FROM table2;
Syntax
MySQL 8.1SELECT column_list FROM table1 UNION ALL SELECT column_list FROM table2;
Beispiel für eine Stored Procedure:
MySQL 8.1CREATE PROCEDURE GetEmployeeByID(IN emp_id INT) BEGIN SELECT * FROM employees WHERE id = emp_id; END;
Aufruf der Prozedur:
MySQL 8.1CALL GetEmployeeByID(1);
Beispiel für eine Funktion:
MySQL 8.1CREATE FUNCTION GetEmployeeSalary(emp_id INT) RETURNS DECIMAL(10,2) BEGIN DECLARE salary DECIMAL(10,2); SELECT e.salary INTO salary FROM employees e WHERE e.id = emp_id; RETURN salary; END;
Verwendung der Funktion:
MySQL 8.1SELECT name, GetEmployeeSalary(id) FROM employees;
Indizes einsetzen:
SELECT * vermeiden:
Bedingungen in JOIN und WHERE optimieren:
Ergebnisse begrenzen (LIMIT):
Subqueries vermeiden, wenn ein Join möglich ist:
Häufig genutzte Daten cachen:
Abfragen profilen und analysieren:
Constraints sichern die Integrität und Zuverlässigkeit der Daten in einer Tabelle, indem sie Regeln für die Werte einzelner Spalten festlegen.
Arten von Constraints:
NOT NULL:
Beispiel:
MySQL 8.1CREATE TABLE products ( product_id INT PRIMARY KEY, name VARCHAR(100) NOT NULL );
UNIQUE:
Beispiel:
MySQL 8.1CREATE TABLE users ( user_id INT PRIMARY KEY, email VARCHAR(100) UNIQUE );
PRIMARY KEY:
FOREIGN KEY:
Beispiel:
MySQL 8.1CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, FOREIGN KEY (user_id) REFERENCES users(user_id) );
CHECK:
Beispiel:
MySQL 8.1CREATE TABLE employees ( id INT PRIMARY KEY, age INT CHECK (age >= 18) );
DEFAULT:
MySQL 8.1CREATE TABLE tasks ( task_id INT PRIMARY KEY, status VARCHAR(20) DEFAULT 'Pending' );
Eine SQL-Injection ist eine Angriffsmethode auf eine Datenbank, bei der ein Angreifer über Eingabefelder schädlichen SQL-Code einschleust und so nicht autorisierte SQL-Abfragen ausführen kann.
1. Prepared Statements (parametrisierte Abfragen):
Beispiel (in Java mit JDBC)
MySQL 8.1String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; PreparedStatement stmt = connection.prepareStatement(sql); stmt.setString(1, username); stmt.setString(2, password); ResultSet rs = stmt.executeQuery();
2. ORM (Object-Relational Mapping) einsetzen:
3. Eingabedaten prüfen und filtern:
4. Zugriffsrechte einschränken:
5. Stored Procedures verwenden:
Eine relationale Datenbank ist eine Datenbank, die auf dem relationalen Datenmodell basiert. In einer solchen Datenbank werden die Daten in Tabellen gespeichert, und die Beziehungen zwischen ihnen werden über Schlüssel definiert.
Beispiel:
MySQL 8.1SELECT * FROM employees e INNER JOIN departments d ON e.department_id = d.id;
LEFT OUTER JOIN (LEFT JOIN):
Beispiel:
MySQL 8.1SELECT * FROM employees e LEFT JOIN departments d ON e.department_id = d.id;
RIGHT OUTER JOIN (RIGHT JOIN):
Beispiel:
MySQL 8.1SELECT * FROM employees e RIGHT JOIN departments d ON e.department_id = d.id;
FULL OUTER JOIN (FULL JOIN):
MySQL 8.1SELECT * FROM employees e FULL OUTER JOIN departments d ON e.department_id = d.id;
NULL ist ein spezieller Wert in SQL, der einen fehlenden oder unbekannten Wert kennzeichnet.
Um auf NULL zu prüfen, nutzt du den Operator IS NULL oder IS NOT NULL.
MySQL 8.1-- Datensätze mit unbekanntem Geburtsdatum finden SELECT * FROM employees WHERE birth_date IS NULL; -- Datensätze mit bekanntem Geburtsdatum finden SELECT * FROM employees WHERE birth_date IS NOT NULL;
COALESCE
Liefert das erste Element der Liste, das nicht NULL ist.
MySQL 8.1COALESCE(val1[, val2, ...., val_n])
ISNULL
Liefert 1 oder 0, je nachdem, ob der Ausdruck NULL ist.
MySQL 8.1ISNULL(value)
IFNULL
Liefert den ersten Wert, sofern dieser nicht NULL ist. Andernfalls wird der zweite Wert zurückgegeben.
MySQL 8.1IFNULL(value, alternative_value)
Der Operator CASE ist das Mittel der Wahl, um bedingte Logik direkt in einer SQL-Abfrage abzubilden. Damit gibst du Werte basierend auf Bedingungen zurück, ganz ähnlich wie mit IF-ELSE.
MySQL 8.1CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... ELSE default_result END
MySQL 8.1SELECT name, salary, CASE WHEN salary >= 80000 THEN 'Hoch' WHEN salary >= 50000 THEN 'Mittel' ELSE 'Niedrig' END AS salary_category FROM employees;
MySQL 8.1BEGIN TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; UPDATE accounts SET balance = balance + 100 WHERE account_id = 2; COMMIT;
MySQL 8.1BEGIN TRANSACTION; DELETE FROM orders WHERE order_date < '2022-01-01'; -- Falls du es dir anders überlegt hast ROLLBACK;
Speicher und Performance:
Einsatzgebiete:
Beispiel:
MySQL 8.1CREATE TABLE products ( code CHAR(10), -- Produktcode mit fester Länge name VARCHAR(100) -- Produktname mit variabler Länge );
Daten einfügen:
MySQL 8.1INSERT INTO products (code, name) VALUES ('A123', 'Lenovo Notebook');
In der Spalte code wird der Wert mit Leerzeichen auf 10 Zeichen aufgefüllt.
Eine temporäre Tabelle ist eine Tabelle, die nur innerhalb der aktuellen Session bzw. Verbindung existiert und automatisch gelöscht wird, sobald die Session endet oder die Verbindung geschlossen wird.
MySQL 8.1CREATE TEMPORARY TABLE TempTable ( id INT, name VARCHAR(100) );
MySQL 8.1-- Daten in die temporäre Tabelle einfügen INSERT INTO #TempTable (id, name) VALUES (1, 'Iwan'), (2, 'Peter'); -- Daten aus der temporären Tabelle lesen SELECT * FROM #TempTable; -- Die temporäre Tabelle wird nach dem Ende der Session automatisch entfernt
Window-Funktionen sind Funktionen, die eine Berechnung über eine Menge von Zeilen (das "Fenster") ausführen, die mit der aktuellen Zeile zusammenhängen, und für jede Zeile ein Ergebnis liefern, ohne die Daten zu gruppieren.
Eine ausführliche Erklärung zur Funktionsweise von Window-Funktionen findest du in unserem Kurs.
Eine CTE (Common Table Expression) ist eine temporäre, benannte Ergebnismenge, die innerhalb einer SQL-Query mit dem Schlüsselwort WITH definiert wird.
Sie verbessert die Lesbarkeit und die Struktur komplexer Queries.
MySQL 8.1WITH CTEName (column1, column2, ...) AS ( -- Deine Query SELECT ... ) SELECT * FROM CTEName;
Eine ausführliche Erklärung zur Funktionsweise von CTEs findest du in unserem Kurs.
Dafür gibt es den Befehl DROP TABLE. Er entfernt die Tabelle samt aller darin gespeicherten Daten aus der Datenbank.
MySQL 8.1DROP TABLE table_name;
Ein FOREIGN KEY ist ein Constraint, das eine Beziehung zwischen einer Spalte oder einer Spaltengruppe einer Tabelle und einer Spalte (bzw. Spalten) einer anderen Tabelle herstellt — in der Regel zum Primary Key der anderen Tabelle.
Er sorgt für referenzielle Integrität, indem er sicherstellt, dass die Werte in der Fremdschlüssel-Spalte zu vorhandenen Werten in der referenzierten Tabelle passen.
Einfügen ungültiger Daten wird verhindert. Es ist nicht möglich, einen Wert in die Fremdschlüssel-Spalte einzutragen, wenn es diesen Wert in der referenzierten Tabelle nicht gibt.
Löschen verknüpfter Datensätze wird eingeschränkt. Ein Datensatz in der übergeordneten Tabelle kann nicht einfach gelöscht werden, solange ihn Datensätze der untergeordneten Tabelle referenzieren — dafür braucht es zusätzliche Regeln.
MySQL 8.1CREATE TABLE Employees ( EmployeeID INT PRIMARY KEY, Name VARCHAR(100), DepartmentID INT, FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID) );
Dafür nutzt du den Befehl ALTER TABLE zusammen mit dem Operator ADD, um der Tabelle eine neue Spalte hinzuzufügen.
MySQL 8.1ALTER TABLE table_name ADD column_name data_type [constraints];
Angenommen, es gibt eine Tabelle employees, und du möchtest die Spalte email vom Typ VARCHAR(255) ergänzen.
MySQL 8.1ALTER TABLE employees ADD email VARCHAR(255);
Spalte mit NOT NULL-Constraint und Default-Wert hinzufügen:
MySQL 8.1ALTER TABLE employees ADD date_of_birth DATE NOT NULL DEFAULT '1900-01-01';
Wichtig: Wenn du eine Spalte mit NOT NULL-Constraint ergänzt und die Tabelle bereits Daten enthält, musst du einen Default-Wert angeben, sonst bekommst du einen Fehler.
Eine korrelierte Subquery ist eine Subquery, die von der äußeren Query abhängt. Sie wird für jede Zeile der äußeren Query erneut ausgeführt und nutzt dabei die Werte aus dieser Zeile.
Es gibt die Tabellen employees und departments.
MySQL 8.1SELECT e.name, e.salary FROM employees e WHERE e.salary > ( SELECT AVG(salary) FROM employees WHERE department_id = e.department_id );
Mehr Infos zu korrelierten Subqueries findest du in unserem Kurs.
MySQL 8.1DELETE FROM table_name [WHERE condition];
MySQL 8.1TRUNCATE TABLE table_name;
MySQL 8.1DROP TABLE table_name;
Ein Self-Join ist ein Join-Typ in SQL, bei dem eine Tabelle mit sich selbst verknüpft wird. Das ist nützlich, wenn du Zeilen derselben Tabelle miteinander vergleichen oder hierarchische Daten verarbeiten möchtest.
Um eine Liste der Mitarbeitenden samt zugehörigem Manager zu erhalten:
MySQL 8.1SELECT e.name AS Employee, m.name AS Manager FROM Employee e LEFT JOIN Employee m ON e.managerId = m.employeeId;
In dieser Query verknüpfen wir die Tabelle Employee mit sich selbst, um jedem Mitarbeitenden den passenden Manager zuzuordnen.
Backup und Restore einer Datenbank sind kritische Aufgaben, um Daten zu sichern und sie im Fall eines Ausfalls oder Datenverlusts wiederherstellen zu können.
Die Backup-Methode hängt vom eingesetzten Datenbankmanagementsystem (DBMS) ab.
Hier ein paar Beispiele für gängige Systeme.
Backup mit dem Tool mysqldump:
MySQL 8.1mysqldump -u username -p mydatabase > backup.sql
Backup mit dem Tool pg_dump:
MySQL 8.1pg_dump -U username mydatabase > backup.sql
Restore aus der Datei backup.sql:
MySQL 8.1mysql -u username -p mydatabase < backup.sql
Restore mit dem Tool psql:
MySQL 8.1psql -U username mydatabase < backup.sql
Many-to-Many-Beziehungen entstehen in relationalen Datenbanken, wenn ein Datensatz aus der ersten Tabelle zu mehreren Datensätzen der zweiten Tabelle gehören kann — und umgekehrt.
In SQL setzt du solche Beziehungen über eine Zwischentabelle um (auch Verknüpfungs- oder Junction-Tabelle genannt), die beide Haupttabellen über Foreign Keys verbindet.
Stell dir ein Szenario mit den Tabellen Student und Course vor: ein Student kann sich für mehrere Kurse anmelden, und ein Kurs kann von mehreren Studierenden besucht werden.
MySQL 8.1CREATE TABLE Student ( StudentID INT PRIMARY KEY, Name VARCHAR(100) );
MySQL 8.1CREATE TABLE Course ( CourseID INT PRIMARY KEY, Title VARCHAR(100) );
MySQL 8.1CREATE TABLE StudentCourse ( StudentID INT, CourseID INT, PRIMARY KEY (StudentID, CourseID), FOREIGN KEY (StudentID) REFERENCES Student(StudentID), FOREIGN KEY (CourseID) REFERENCES Course(CourseID) );
Ergebnis:
Die Befehle GRANT und REVOKE dienen in SQL dazu, die Zugriffsrechte von Benutzern auf Datenbankobjekte zu steuern. Damit erteilst oder entziehst du Benutzern oder Rollen bestimmte Privilegien und sorgst so für Sicherheit und Kontrolle darüber, wer welche Aktionen in der Datenbank ausführen darf.
Mit GRANT weist du Benutzern oder Rollen bestimmte Privilegien auf Datenbankobjekte zu.
MySQL 8.1GRANT privileges ON object TO user [WITH GRANT OPTION];
Beispiel: So gibst du dem Benutzer user1 das Recht, Daten aus der Tabelle employees zu lesen:
MySQL 8.1GRANT SELECT ON employees TO user1;
Mit REVOKE ziehst du zuvor erteilte Privilegien von Benutzern oder Rollen wieder ein.
MySQL 8.1REVOKE privileges ON object FROM user;
Beispiel: So entziehst du user1 das Recht, aus der Tabelle employees zu lesen:
MySQL 8.1REVOKE SELECT ON employees FROM user1;
Hash-Funktionen werden in SQL eingesetzt, um Eingabedaten beliebiger Länge in einen String fester Länge umzuwandeln. Diesen Vorgang nennt man Hashing. Er wird breit eingesetzt, um Sicherheit zu erhöhen, Datenintegrität sicherzustellen und Vergleichs- bzw. Suchoperationen zu beschleunigen.
Mit Hash-Funktionen kannst du erkennen, ob Daten verändert wurden. Du bildest einen Hash über die Originaldaten und vergleichst ihn mit dem aktuellen Hash — passt etwas nicht, hat sich etwas geändert.
Hash-Werte eignen sich gut, um große Datenmengen schnell zu vergleichen oder Indizes für eine performantere Suche aufzubauen.
Hashing hilft dabei, eindeutige Identifier für Datensätze auf Basis ihres Inhalts zu generieren.
MySQL 8.1-- Tabelle für Benutzer anlegen CREATE TABLE Users ( UserID INT PRIMARY KEY, Username VARCHAR(50) NOT NULL, PasswordHash VARBINARY(512) NOT NULL ); -- Beim Anlegen eines neuen Benutzers hashen wir das Passwort INSERT INTO Users (UserID, Username, PasswordHash) VALUES (1, 'user1', HASHBYTES('SHA2_512', 'password123')); -- Prüfen, ob das eingegebene Passwort zum gespeicherten Hash passt SELECT UserID FROM Users WHERE Username = 'user1' AND PasswordHash = HASHBYTES('SHA2_512', 'password123');
Speichere Hashes binär (VARBINARY) statt als String (VARCHAR), das schont Speicher und vermeidet Genauigkeitsverluste.
Denk dran: Hashing ist eine Einwegfunktion. Aus einem Hash lassen sich die Originaldaten nicht rekonstruieren.
Ein SQL-Trigger ist ein Datenbankobjekt — eine spezielle Form einer Stored Procedure, die automatisch ausgeführt wird, sobald in der Datenbank ein bestimmtes Ereignis eintritt. Solche Ereignisse können INSERT-, UPDATE- oder DELETE-Operationen auf Tabellen oder Views sein.
Ein Trigger wird automatisch aktiviert, sobald das definierte Ereignis eintritt (zum Beispiel das Einfügen eines neuen Datensatzes in eine Tabelle).
Innerhalb eines Triggers kannst du über die speziellen Pseudo-Tabellen OLD und NEW auf die alten und neuen Werte zugreifen.
Du hast eine Tabelle Employees und möchtest die Gehaltshistorie der Mitarbeitenden bei jeder Änderung automatisch in einer Tabelle SalaryHistory festhalten.
Tabellen anlegen:
MySQL 8.1-- Tabelle der Mitarbeitenden CREATE TABLE Employees ( EmployeeID INT PRIMARY KEY, Name VARCHAR(100), Salary DECIMAL(10, 2) ); -- Tabelle für die Gehaltshistorie CREATE TABLE SalaryHistory ( EmployeeID INT, OldSalary DECIMAL(10, 2), NewSalary DECIMAL(10, 2), ChangeDate DATETIME DEFAULT CURRENT_TIMESTAMP );
Trigger anlegen:
MySQL 8.1DELIMITER $$ CREATE TRIGGER trg_AfterSalaryUpdate AFTER UPDATE ON Employees FOR EACH ROW BEGIN IF OLD.Salary <> NEW.Salary THEN INSERT INTO SalaryHistory (EmployeeID, OldSalary, NewSalary) VALUES (NEW.EmployeeID, OLD.Salary, NEW.Salary); END IF; END$$ DELIMITER ;