15 von 16

Referenz · Kapitel 15 von 16

PHP · MySQL · HTML/CSS – Schritt für Schritt

Referenz

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 x NULL ist (etwa weil order_items leer), 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;
Klassischer Fehler: INNER JOIN statt LEFT JOIN nehmen. Dann fehlen die Produkte, die NIE bestellt wurden – genau die aber sind die eigentlichen Flops. LEFT JOIN + COALESCE macht 0 aus fehlenden Werten.

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.
Einbau in statistiken.php: die drei Queries oben mit $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.

16 Kapitel · ein Projekt

Der Codeinander Lernpfad

DEEN in Vorbereitung

Grundlagen

01GrundlagenIntro & Setup 02GrundlagenDatenbank-Schema 03Grundlagendb.php – Verbindung

Auth

04Authregister.php 05Authlogin.php 06Authlogout.php

Shop

07Shopnavbar.php 08Shopindex.php – Liste 09Shopproductdetail.php

Warenkorb

10Warenkorbcart_add.php 11Warenkorbwarenkorb.php 12Warenkorbcart_remove.php

Admin

13Adminstatistiken.php + Admin 14Admincheckout.php + Rechnung

Referenz

15ReferenzSQL-Cheatsheet 16Referenzzertifizierung-Checkliste