Zum Inhalt springen
BeispielWerk
English

SQL Beispiele für PostgreSQL, MySQL und SQLite

SQL ist die Abfragesprache für relationale Datenbanken; die Schreibweise unterscheidet sich je nach System. Die Snippets bauen ein kleines Shop-Schema aus Kunden, Produkten und Bestellungen auf und zeigen dazu INSERT, UPSERT, JOIN, CTE, Paginierung, Indizes und Datumsfunktionen für PostgreSQL, MySQL und SQLite. Die Hinweise nennen, ob ein Snippet ausgeführt oder nur nach der Referenz geschrieben wurde.

48 Varianten auf einer Seite, jede mit eigenem Kopier- oder Download-Knopf. Darunter: 9× Fiktiv, 2× Absichtlich ungültig.

  • SQL PostgreSQL: CREATE TABLE kunden

    CREATE TABLE kunden (
      id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
      kundennummer  TEXT        NOT NULL UNIQUE, …

    Auf PostgreSQL 17 ausgeführt. Geld als NUMERIC, nicht als float.

  • SQL PostgreSQL: CREATE TABLE produkte

    CREATE TABLE produkte (
      id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
      sku         TEXT          NOT NULL UNIQUE, …

    Auf PostgreSQL 17 ausgeführt. Geld als NUMERIC, nicht als float.

  • SQL PostgreSQL: CREATE TABLE bestellungen

    CREATE TABLE bestellungen (
      id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
      kunde_id     BIGINT      NOT NULL REFERENCES kunden (id) ON DELETE RESTRICT, …

    Auf PostgreSQL 17 ausgeführt. Geld als NUMERIC, nicht als float.

  • SQL PostgreSQL: CREATE TABLE bestellpositionen

    CREATE TABLE bestellpositionen (
      bestellung_id BIGINT        NOT NULL REFERENCES bestellungen (id) ON DELETE CASCADE,
      position      INTEGER       NOT NULL, …

    Auf PostgreSQL 17 ausgeführt. Geld als NUMERIC, nicht als float.

  • SQL PostgreSQL: Shop-Schema komplett (4 Tabellen)

    CREATE TABLE kunden (
      id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
      kundennummer  TEXT        NOT NULL UNIQUE, …

    Auf PostgreSQL 17 ausgeführt. Geld als NUMERIC, nicht als float.

  • SQL MySQL: CREATE TABLE kunden

    CREATE TABLE kunden (
      id           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
      kundennummer VARCHAR(20)  NOT NULL UNIQUE, …

    Nach der MySQL-8.0-Referenz geschrieben, nicht ausgeführt. CHECK wird ab 8.0.16 erzwungen, DEFAULT (CURRENT_DATE) ab 8.0.13.

  • SQL MySQL: CREATE TABLE produkte

    CREATE TABLE produkte (
      id          BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
      sku         VARCHAR(40)   NOT NULL UNIQUE, …

    Nach der MySQL-8.0-Referenz geschrieben, nicht ausgeführt. CHECK wird ab 8.0.16 erzwungen, DEFAULT (CURRENT_DATE) ab 8.0.13.

  • SQL MySQL: CREATE TABLE bestellungen

    CREATE TABLE bestellungen (
      id           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
      kunde_id     BIGINT UNSIGNED NOT NULL, …

    Nach der MySQL-8.0-Referenz geschrieben, nicht ausgeführt. CHECK wird ab 8.0.16 erzwungen, DEFAULT (CURRENT_DATE) ab 8.0.13.

  • SQL MySQL: CREATE TABLE bestellpositionen

    CREATE TABLE bestellpositionen (
      bestellung_id BIGINT UNSIGNED NOT NULL,
      position      INT             NOT NULL, …

    Nach der MySQL-8.0-Referenz geschrieben, nicht ausgeführt. CHECK wird ab 8.0.16 erzwungen, DEFAULT (CURRENT_DATE) ab 8.0.13.

  • SQL MySQL: Shop-Schema komplett (4 Tabellen)

    CREATE TABLE kunden (
      id           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
      kundennummer VARCHAR(20)  NOT NULL UNIQUE, …

    Nach der MySQL-8.0-Referenz geschrieben, nicht ausgeführt. CHECK wird ab 8.0.16 erzwungen, DEFAULT (CURRENT_DATE) ab 8.0.13.

  • SQL SQLite: CREATE TABLE kunden

    CREATE TABLE kunden (
      id           INTEGER PRIMARY KEY AUTOINCREMENT,
      kundennummer TEXT NOT NULL UNIQUE, …

    Mit SQLite ausgeführt. Fremdschlüssel greifen erst nach PRAGMA foreign_keys = ON. Geld besser als ganze Cent speichern.

  • SQL SQLite: CREATE TABLE produkte

    CREATE TABLE produkte (
      id          INTEGER PRIMARY KEY AUTOINCREMENT,
      sku         TEXT    NOT NULL UNIQUE, …

    Mit SQLite ausgeführt. Fremdschlüssel greifen erst nach PRAGMA foreign_keys = ON. Geld besser als ganze Cent speichern.

  • SQL SQLite: CREATE TABLE bestellungen

    CREATE TABLE bestellungen (
      id           INTEGER PRIMARY KEY AUTOINCREMENT,
      kunde_id     INTEGER NOT NULL REFERENCES kunden (id) ON DELETE RESTRICT, …

    Mit SQLite ausgeführt. Fremdschlüssel greifen erst nach PRAGMA foreign_keys = ON. Geld besser als ganze Cent speichern.

  • SQL SQLite: CREATE TABLE bestellpositionen

    CREATE TABLE bestellpositionen (
      bestellung_id INTEGER NOT NULL REFERENCES bestellungen (id) ON DELETE CASCADE,
      position      INTEGER NOT NULL, …

    Mit SQLite ausgeführt. Fremdschlüssel greifen erst nach PRAGMA foreign_keys = ON. Geld besser als ganze Cent speichern.

  • SQL SQLite: Shop-Schema komplett (4 Tabellen)

    PRAGMA foreign_keys = ON;
    
    CREATE TABLE kunden ( …

    Mit SQLite ausgeführt. Fremdschlüssel greifen erst nach PRAGMA foreign_keys = ON. Geld besser als ganze Cent speichern.

  • SQL: INSERT mit drei KundenFiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES
      ('K-100001', 'Anna', 'Müller', 'anna.mueller@example.com', 'Musterstadt'), …

    Läuft unverändert in PostgreSQL, MySQL und SQLite.

  • SQL: INSERT mit vier Produkten (netto, MwSt 19 und 7)Fiktiv

    INSERT INTO produkte (sku, name, preis_netto, mwst_satz, bestand)
    VALUES
      ('SKU-1001', 'Notizbuch A5', 4.90, 19, 120), …

    Läuft unverändert in PostgreSQL, MySQL und SQLite. Hier gelten nur Beispielpreise.

  • SQL: Bestellung mit zwei Positionen anlegenFiktiv

    INSERT INTO bestellungen (kunde_id, bestelldatum, status)
    VALUES (1, '2026-10-09', 'offen');
     …

    Setzt voraus, dass Kunde 1 und Produkte 1 und 2 existieren und die Bestellung die ID 1 bekommt.

  • SQL: INSERT mit Apostroph und Umlauten im TextFiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES ('K-100004', 'Conan', 'O''Brien', 'conan.obrien@example.com', 'Düsseldorf-Größenwahn');

    Ein Apostroph im Text wird im SQL-Standard verdoppelt. In Programmcode besser Parameter verwenden.

  • SQL PostgreSQL: UPSERT mit ON CONFLICTFiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES ('K-100001', 'Anna', 'Müller', 'anna.mueller@example.com', 'Neustadt')
    ON CONFLICT (kundennummer) DO UPDATE …

    Auf PostgreSQL 17 ausgeführt. Braucht einen UNIQUE-Index auf kundennummer. Mit DO NOTHING bleibt die vorhandene Zeile unverändert.

  • SQL SQLite: UPSERT mit ON CONFLICTFiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES ('K-100001', 'Anna', 'Müller', 'anna.mueller@example.com', 'Neustadt')
    ON CONFLICT (kundennummer) DO UPDATE …

    Mit SQLite 3.24 oder neuer ausgeführt.

  • SQL MySQL: UPSERT mit ON DUPLICATE KEY UPDATEFiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES ('K-100001', 'Anna', 'Müller', 'anna.mueller@example.com', 'Neustadt') AS neu
    ON DUPLICATE KEY UPDATE …

    Nach der MySQL-8.0.19-Referenz (Alias statt des veralteten VALUES()), nicht ausgeführt. MariaDB kennt den Alias nicht.

  • SQL MySQL/MariaDB: UPSERT mit VALUES() (ältere Schreibweise)Fiktiv

    INSERT INTO kunden (kundennummer, vorname, nachname, email, ort)
    VALUES ('K-100001', 'Anna', 'Müller', 'anna.mueller@example.com', 'Neustadt')
    ON DUPLICATE KEY UPDATE …

    Nicht ausgeführt. Seit MySQL 8.0.20 als veraltet markiert, in MariaDB weiterhin üblich.

  • SQL PostgreSQL 15+: MERGEFiktiv

    MERGE INTO produkte AS p
    USING (VALUES ('SKU-1001', 25)) AS neu (sku, zugang)
    ON p.sku = neu.sku …

    Auf PostgreSQL 17 ausgeführt; MERGE gibt es ab Version 15.

  • SQL: Bestand verringern, ohne unter 0 zu fallen

    UPDATE produkte
    SET bestand = bestand - 3
    WHERE sku = 'SKU-1001' …

    Die Bedingung bestand >= 3 verhindert Überverkauf auch bei gleichzeitigen Zugriffen; prüfen, ob eine Zeile geändert wurde.

  • SQL: DELETE mit Bedingung und Kontrollabfrage

    -- erst zählen
    SELECT COUNT(*) FROM bestellungen WHERE status = 'storniert' AND bestelldatum < '2025-01-01';
     …
  • SQL: Kunden mit ihren Bestellungen (JOIN)

    SELECT k.kundennummer, k.nachname, b.id AS bestellung, b.bestelldatum, b.status
    FROM kunden AS k
    JOIN bestellungen AS b ON b.kunde_id = k.id …
  • SQL: Kunden ohne Bestellung finden (LEFT JOIN)

    SELECT k.kundennummer, k.vorname, k.nachname
    FROM kunden AS k
    LEFT JOIN bestellungen AS b ON b.kunde_id = k.id …
  • SQL: Umsatz je Bestellung mit GROUP BY

    SELECT bestellung_id,
           COUNT(*)                 AS positionen,
           SUM(menge * einzelpreis) AS summe_netto …
  • SQL: WITH-Abfrage (CTE) für Umsatz pro Kunde

    WITH summen AS (
      SELECT bestellung_id, SUM(menge * einzelpreis) AS netto
      FROM bestellpositionen …
  • SQL: Fensterfunktion ROW_NUMBER je Kunde

    SELECT kunde_id, id AS bestellung, bestelldatum,
           ROW_NUMBER() OVER (PARTITION BY kunde_id ORDER BY bestelldatum DESC) AS nr
    FROM bestellungen;

    Fensterfunktionen gibt es in PostgreSQL, MySQL ab 8.0 und SQLite ab 3.25.

  • SQL: Seitenweise Abfrage mit LIMIT und OFFSET

    SELECT id, nachname
    FROM kunden
    ORDER BY id …

    Seite 3 bei 20 Einträgen pro Seite. Bei großen Tabellen wird hohes OFFSET langsam.

  • SQL: Seitenweise Abfrage mit Keyset (nach letzter ID)

    SELECT id, nachname
    FROM kunden
    WHERE id > 40 …
  • SQL: Transaktion mit Rollback-Möglichkeit

    BEGIN;
    
    UPDATE produkte SET bestand = bestand - 1 WHERE sku = 'SKU-1001' AND bestand >= 1; …

    In MySQL heißt der Beginn START TRANSACTION (BEGIN funktioniert ebenfalls).

  • SQL: Index, zusammengesetzter Index und eindeutiger Index

    CREATE INDEX idx_kunden_nachname ON kunden (nachname);
    CREATE INDEX idx_kunden_ort_nachname ON kunden (ort, nachname);
    CREATE UNIQUE INDEX idx_produkte_sku ON produkte (sku);
  • SQL: Spalte hinzufügen, Standardwert setzen

    ALTER TABLE kunden ADD COLUMN telefon VARCHAR(30);
    ALTER TABLE kunden ADD COLUMN newsletter BOOLEAN NOT NULL DEFAULT FALSE;

    VARCHAR/BOOLEAN laufen in PostgreSQL, MySQL und SQLite; SQLite kann mehrere Änderungen nicht in einer ALTER-Anweisung bündeln.

  • SQL: Soft Delete mit Spalte geloescht_am

    ALTER TABLE kunden ADD COLUMN geloescht_am TIMESTAMP NULL;
    
    UPDATE kunden SET geloescht_am = CURRENT_TIMESTAMP WHERE kundennummer = 'K-100003'; …
  • SQL: LIKE mit maskiertem Prozentzeichen

    SELECT * FROM produkte WHERE name LIKE '100!%%' ESCAPE '!';

    Findet Namen, die mit "100%" beginnen. ESCAPE legt das Maskierungszeichen fest.

  • SQL: NULL richtig vergleichen

    SELECT * FROM kunden WHERE email IS NULL;
    SELECT * FROM kunden WHERE email IS NOT NULL;
    SELECT COALESCE(email, 'keine E-Mail') FROM kunden; …
  • SQL: CASE-Ausdruck für Statustexte

    SELECT id,
      CASE status
        WHEN 'offen' THEN 'Wartet auf Zahlung' …
  • SQL: Brutto aus Netto berechnen und runden

    SELECT sku, name, preis_netto, mwst_satz,
           ROUND(preis_netto * (1 + mwst_satz / 100), 2) AS preis_brutto
    FROM produkte;
  • SQL PostgreSQL: Datumsfunktionen

    SELECT now(), CURRENT_DATE,
           date_trunc('month', now()) AS monatsanfang,
           CURRENT_DATE - INTERVAL '30 days' AS vor_30_tagen, …

    Auf PostgreSQL 17 ausgeführt.

  • SQL MySQL: Datumsfunktionen

    SELECT NOW(), CURDATE(),
           DATE_FORMAT(NOW(), '%d.%m.%Y') AS deutsch,
           DATE_SUB(CURDATE(), INTERVAL 30 DAY) AS vor_30_tagen, …

    Nach der MySQL-Referenz geschrieben, nicht ausgeführt.

  • SQL SQLite: Datumsfunktionen

    SELECT datetime('now'), date('now'),
           strftime('%d.%m.%Y', 'now') AS deutsch,
           date('now', '-30 days') AS vor_30_tagen, …

    Mit SQLite ausgeführt.

  • SQL PostgreSQL: JSONB-Spalte abfragen

    CREATE TABLE ereignisse (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, daten JSONB NOT NULL);
    INSERT INTO ereignisse (daten) VALUES ('{"typ": "login", "nutzer": {"id": 7, "name": "Anna"}}');
    SELECT daten->>'typ' AS typ, daten->'nutzer …

    Auf PostgreSQL 17 ausgeführt.

  • SQL SQLite: JSON-Funktionen

    SELECT json_extract('{"typ": "login", "nutzer": {"id": 7}}', '$.nutzer.id') AS id,
           json_array_length('[1,2,3]') AS anzahl;

    Mit SQLite ausgeführt (JSON-Funktionen sind in aktuellen Versionen eingebaut).

  • Ungültiges SQL: Komma vor FROMAbsichtlich ungültig

    SELECT id, nachname, FROM kunden;
  • Ungültiges SQL: Zeichenkette nicht geschlossenAbsichtlich ungültig

    SELECT * FROM kunden WHERE nachname = 'O'Brien';

    Der Apostroph muss verdoppelt werden (O''Brien) oder als Parameter übergeben werden.

Weitere Themen in Datenformate & Snippets