SQL-Cheatsheet – jede Query erklärt
Hier sind alle SQL-Queries aus dem Projekt, einzeln erklärt. Zusätzlich die drei Ranking-Queries, die die zertifizierung-Angabe explizit verlangt.
1. SELECT mit WHERE + Prepared Statement
SELECT id, name, price, description, picture FROM products WHERE freigeben = 1 AND category_id = ?
Holt alle Spalten aus products, aber nur freigegebene (freigeben = 1) UND aus einer bestimmten Kategorie. Das ? ist ein Platzhalter fürs Prepared Statement. Verwendet in index.php.
2. SELECT ohne Filter (query statt prepare)
SELECT id, name, price, description, picture FROM products WHERE freigeben = 1
Gleiches Prinzip, aber ohne Parameter. Deshalb kein Prepared Statement nötig – $conn->query(...) reicht. Verwendet in index.php für den ungefilterten Pfad.
3. SELECT mit LIKE / mehreren Bedingungen
SELECT id, name, price, description, picture, artikelcode FROM products WHERE id = ? AND freigeben = 1
Findet ein einzelnes Produkt anhand seiner ID – aber nur, wenn es freigegeben ist. AND verknüpft beide Bedingungen. Verwendet in productdetail.php.
4. INSERT mit Prepared Statement
INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)
Legt einen neuen User an. Die drei ? werden per execute([$username, $email, $hash]) gefüllt. Reihenfolge muss stimmen. Danach liefert $conn->lastInsertId() die neue ID.
5. UPDATE mit Toggle-Trick
UPDATE products SET freigeben = 1 - freigeben WHERE id = ?
Wechselt den Freigabe-Status: aus 1 wird 0, aus 0 wird 1 (weil 1 - 1 = 0 und 1 - 0 = 1). Ein einziges Statement für beide Richtungen. Verwendet im Admin-Bereich.
6. DELETE mit Prepared Statement
DELETE FROM products WHERE id = ?
Löscht ein Produkt. Wichtig: kann eine Exception werfen, wenn das Produkt bereits in order_items referenziert wird (Foreign Key Constraint). Deshalb immer in try/catch.
7. IN-Query mit dynamischen Platzhaltern
SELECT id, name, price, picture FROM products WHERE id IN (?,?,?)
Holt mehrere Produkte auf einmal. Anzahl der ? wird zur Laufzeit mit array_fill() und implode() erzeugt. Verwendet in warenkorb.php.
8. JOIN – Tabellen verknüpfen
SELECT p.id, p.name, p.artikelcode, p.price, p.freigeben, c.name AS kategorie_name FROM products p LEFT JOIN categories c ON c.id = p.category_id ORDER BY p.id DESC
Verknüpft die Produkte mit ihrer Kategorie. LEFT JOIN (statt INNER JOIN) sorgt dafür, dass auch Produkte OHNE Kategorie noch angezeigt werden (kategorie_name ist dann NULL). p und c sind Aliase, um die Query kürzer zu machen. AS kategorie_name benennt die Spalte im Ergebnis um. Verwendet im Admin-Bereich.
9. Aggregat-Funktionen (COUNT, SUM, COALESCE)
SELECT COUNT(*) FROM users; SELECT COUNT(*) FROM products; SELECT COUNT(*) FROM orders; SELECT COALESCE(SUM(menge * preis), 0) FROM order_items;
- COUNT(*) – zählt Zeilen.
- SUM(menge * preis) – Summe über alle Zeilen, wobei zuerst Menge mal Preis pro Zeile ausgerechnet wird.
- COALESCE(x, 0) – wenn
xNULL ist (etwa weilorder_itemsleer), wird stattdessen 0 zurückgegeben. Verhindert PHP-Fehler bei leeren Tabellen. - fetchColumn() holt nur die erste Spalte der ersten Zeile – perfekt für einzelne Werte.
10. INSERT + Transaktion (für Bestellung)
-- 1. bestellung anlegen INSERT INTO orders (user_id) VALUES (?) -- 2. für jedes produkt eine position INSERT INTO order_items (order_id, product_id, menge, preis) VALUES (?, ?, ?, ?)
Muss atomar passieren, deshalb in PHP:
$conn->beginTransaction();
try {
// beide INSERTs
$conn->commit();
} catch (Exception $e) {
$conn->rollBack();
}11. Top 5 meistbestellte Produkte (zertifizierung-Anforderung f)
SELECT p.name, SUM(oi.menge) AS verkauft FROM order_items oi JOIN products p ON p.id = oi.product_id GROUP BY p.id, p.name ORDER BY verkauft DESC LIMIT 5;
- JOIN – Positionen mit Produkten verknüpfen (wir wollen den Namen sehen, nicht nur die ID).
- SUM(oi.menge) – Mengen aller Bestellpositionen eines Produkts addieren.
- GROUP BY p.id, p.name – nach Produkt gruppieren, sonst wäre SUM sinnlos.
- ORDER BY verkauft DESC – meistverkaufte zuerst.
- LIMIT 5 – nur die Top 5.
12. Flop 5 (5 am seltensten bestellten Produkte)
SELECT p.name, COALESCE(SUM(oi.menge), 0) AS verkauft FROM products p LEFT JOIN order_items oi ON oi.product_id = p.id GROUP BY p.id, p.name ORDER BY verkauft ASC LIMIT 5;
13. Bestellverlauf letzte 4 Wochen (zertifizierung-Anforderung f)
SELECT DATE(bestellt_am) AS tag,
COUNT(*) AS anzahl_bestellungen
FROM orders
WHERE bestellt_am >= NOW() - INTERVAL 28 DAY
GROUP BY DATE(bestellt_am)
ORDER BY tag;- DATE(bestellt_am) – ignoriert die Uhrzeit, gruppiert pro Tag.
- NOW() - INTERVAL 28 DAY – der Zeitpunkt vor 28 Tagen (= 4 Wochen).
- GROUP BY DATE(bestellt_am) – ein Ergebnis pro Tag.
- ORDER BY tag – chronologisch von alt nach neu.
$conn->query(...)->fetchAll(PDO::FETCH_ASSOC) ausführen und dann als Tabellen ausgeben. Muster ist genau wie bei $alle_produkte.14. WHERE mit LIKE für Suche (nützlich als Bonus)
SELECT * FROM products WHERE name LIKE ?
Aufruf: $stmt->execute(['%'.$suche.'%']). Die Prozentzeichen sind Wildcards (beliebige Zeichen davor/danach). Auch im Prepared Statement escaped, deshalb sicher.