SQL (Structured Query Language) ist die Standardsprache für relationale Datenbanken. Diese Grundlagen gelten für MySQL, MariaDB, PostgreSQL und andere.
Datenbankverbindung
MySQL/MariaDB
mysql -u username -p datenbanknamePostgreSQL
psql -U username -d datenbanknameSELECT - Daten abfragen
Grundlegende Abfragen
-- Alle Spalten
SELECT * FROM users;
-- Bestimmte Spalten
SELECT id, name, email FROM users;
-- Mit Alias
SELECT name AS benutzername, email AS mailadresse FROM users;WHERE - Filtern
-- Einfache Bedingung
SELECT * FROM users WHERE active = 1;
-- Mehrere Bedingungen
SELECT * FROM users WHERE active = 1 AND age >= 18;
SELECT * FROM users WHERE city = 'Berlin' OR city = 'Hamburg';
-- Vergleichsoperatoren
SELECT * FROM products WHERE price > 100;
SELECT * FROM products WHERE price >= 50 AND price <= 100;
SELECT * FROM products WHERE price BETWEEN 50 AND 100;
-- NULL-Werte
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;LIKE - Textsuche
-- Beginnt mit
SELECT * FROM users WHERE name LIKE 'Max%';
-- Endet mit
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- Enthält
SELECT * FROM users WHERE name LIKE '%mueller%';
-- Ein einzelnes Zeichen
SELECT * FROM users WHERE name LIKE 'M_yer';IN - Mehrere Werte
SELECT * FROM users
WHERE country IN ('Deutschland', 'Österreich', 'Schweiz');ORDER BY - Sortieren
-- Aufsteigend (Standard)
SELECT * FROM users ORDER BY name;
SELECT * FROM users ORDER BY name ASC;
-- Absteigend
SELECT * FROM users ORDER BY created_at DESC;
-- Mehrere Spalten
SELECT * FROM users ORDER BY country, city, name;LIMIT - Anzahl begrenzen
-- Erste 10 Ergebnisse
SELECT * FROM users LIMIT 10;
-- 10 Ergebnisse ab Position 20 (Pagination)
SELECT * FROM users LIMIT 10 OFFSET 20;
-- MySQL Kurzform:
SELECT * FROM users LIMIT 20, 10;DISTINCT - Eindeutige Werte
SELECT DISTINCT country FROM users;
SELECT DISTINCT country, city FROM users;INSERT - Daten einfügen
Einzelner Datensatz
-- Alle Spalten (nicht empfohlen)
INSERT INTO users VALUES (1, 'Max', 'max@example.com');
-- Mit Spaltennamen (empfohlen)
INSERT INTO users (name, email) VALUES ('Max', 'max@example.com');
-- Mehrere Spalten
INSERT INTO products (name, price, category_id, stock)
VALUES ('Laptop', 999.99, 1, 50);Mehrere Datensätze
INSERT INTO users (name, email) VALUES
('Max', 'max@example.com'),
('Anna', 'anna@example.com'),
('Peter', 'peter@example.com');INSERT mit SELECT
-- Daten aus anderer Tabelle kopieren
INSERT INTO archive_users (id, name, email)
SELECT id, name, email FROM users WHERE active = 0;UPDATE - Daten aktualisieren
Grundlegendes Update
-- IMMER mit WHERE!
UPDATE users SET active = 0 WHERE id = 5;
-- Mehrere Spalten
UPDATE users SET name = 'Maximilian', email = 'max@neu.de' WHERE id = 5;Berechnungen
-- Wert erhöhen
UPDATE products SET stock = stock - 1 WHERE id = 10;
UPDATE products SET price = price * 1.1; -- 10% Erhöhung (ALLE!)
-- Bedingte Aktualisierung
UPDATE products SET stock = stock - 1 WHERE id = 10 AND stock > 0;WICHTIG: WHERE nicht vergessen!
-- GEFÄHRLICH: Aktualisiert ALLE Datensätze!
UPDATE users SET active = 0;
-- Sicher: Nur bestimmte Datensätze
UPDATE users SET active = 0 WHERE last_login < '2024-01-01';DELETE - Daten löschen
Datensätze löschen
-- IMMER mit WHERE!
DELETE FROM users WHERE id = 5;
-- Mit Bedingung
DELETE FROM users WHERE active = 0 AND created_at < '2023-01-01';WICHTIG: WHERE nicht vergessen!
-- GEFÄHRLICH: Löscht ALLE Datensätze!
DELETE FROM users;
-- Sicher: Nur bestimmte Datensätze
DELETE FROM users WHERE id = 5;TRUNCATE - Alle Daten löschen
-- Schneller als DELETE, setzt Auto-Increment zurück
TRUNCATE TABLE old_logs;Aggregatfunktionen
Zählen, Summe, Durchschnitt
-- Anzahl
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM users WHERE active = 1;
SELECT COUNT(DISTINCT country) FROM users;
-- Summe
SELECT SUM(price) FROM orders WHERE user_id = 5;
-- Durchschnitt
SELECT AVG(price) FROM products;
-- Minimum/Maximum
SELECT MIN(price), MAX(price) FROM products;GROUP BY - Gruppieren
-- Anzahl pro Kategorie
SELECT category_id, COUNT(*)
FROM products
GROUP BY category_id;
-- Mit Spaltennamen
SELECT c.name, COUNT(p.id) as product_count
FROM categories c
LEFT JOIN products p ON c.id = p.category_id
GROUP BY c.id, c.name;HAVING - Gruppen filtern
-- Kategorien mit mehr als 10 Produkten
SELECT category_id, COUNT(*) as count
FROM products
GROUP BY category_id
HAVING COUNT(*) > 10;JOINs - Tabellen verknüpfen
INNER JOIN
-- Nur übereinstimmende Datensätze
SELECT users.name, orders.total
FROM users
INNER JOIN orders ON users.id = orders.user_id;LEFT JOIN
-- Alle Users, auch ohne Orders
SELECT users.name, orders.total
FROM users
LEFT JOIN orders ON users.id = orders.user_id;RIGHT JOIN
-- Alle Orders, auch ohne User
SELECT users.name, orders.total
FROM users
RIGHT JOIN orders ON users.id = orders.user_id;Mehrere JOINs
SELECT
u.name,
o.id as order_id,
p.name as product_name,
oi.quantity
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN order_items oi ON o.id = oi.order_id
INNER JOIN products p ON oi.product_id = p.id
WHERE o.created_at >= '2024-01-01';Subqueries
-- In WHERE
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE total > 100);
-- In SELECT
SELECT
name,
(SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count
FROM users;
-- In FROM
SELECT avg_price
FROM (SELECT AVG(price) as avg_price FROM products) as subquery;Praktische Beispiele
Top 10 Kunden nach Umsatz
SELECT
u.name,
SUM(o.total) as total_spent
FROM users u
INNER JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY total_spent DESC
LIMIT 10;Produkte die noch nie verkauft wurden
SELECT p.*
FROM products p
LEFT JOIN order_items oi ON p.id = oi.product_id
WHERE oi.id IS NULL;Umsatz pro Monat
SELECT
DATE_FORMAT(created_at, '%Y-%m') as month,
SUM(total) as revenue
FROM orders
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY month;Benutzer mit letztem Login
SELECT
name,
email,
DATEDIFF(NOW(), last_login) as days_since_login
FROM users
WHERE last_login < DATE_SUB(NOW(), INTERVAL 30 DAY);Tipps
Performance
-- Index nutzen (WHERE auf indexierte Spalten)
SELECT * FROM users WHERE email = 'test@example.com';
-- EXPLAIN zeigt Query-Plan
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- LIKE mit Wildcard am Anfang ist langsam
SELECT * FROM users WHERE name LIKE '%mueller%'; -- Langsam
SELECT * FROM users WHERE name LIKE 'mueller%'; -- SchnellerSicherheit
-- NIEMALS User-Input direkt einsetzen!
-- Falsch (SQL-Injection möglich):
"SELECT * FROM users WHERE name = '" + userName + "'"
-- Richtig: Prepared Statements verwenden
-- PHP PDO:
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute([$userName]);Fazit
Die Grundbefehle SELECT, INSERT, UPDATE und DELETE decken den größten Teil der täglichen Datenbankarbeit ab. Achten Sie besonders bei UPDATE und DELETE auf die WHERE-Klausel. JOINs sind wichtig für relationale Daten, und Aggregatfunktionen ermöglichen aussagekräftige Auswertungen. Für produktiven Einsatz sollten Sie immer Prepared Statements verwenden, um SQL-Injection zu verhindern.