Zum Inhalt springen
SQL Anfänger 25 min

CREATE TABLE

Lerne, wie du eigene Tabellen erstellst: Spalten definieren, Datentypen wählen und die richtige Struktur planen.

Aktualisiert:

Bisher hast du mit vorbereiteten Tabellen gearbeitet. Jetzt lernst du, wie du eigene Tabellen erstellst - mit genau den Spalten, Datentypen und Einschraenkungen, die du brauchst.

Grundsyntax von CREATE TABLE

CREATE TABLE tabellenname (
    spaltenname1 datentyp [einschraenkungen],
    spaltenname2 datentyp [einschraenkungen],
    ...
);

Deine erste eigene Tabelle

CREATE TABLE kontakte (
    id INTEGER PRIMARY KEY,
    vorname TEXT NOT NULL,
    nachname TEXT NOT NULL,
    email TEXT UNIQUE,
    telefon TEXT,
    erstellt_am DATE DEFAULT CURRENT_DATE
);

Jede Spalte hat:

  • Einen Namen (z.B. vorname)
  • Einen Datentyp (z.B. TEXT)
  • Optionale Einschraenkungen (z.B. NOT NULL, UNIQUE)

Wichtige Datentypen

Die gaengigsten Datentypen, die in SQLite und PostgreSQL funktionieren:

DatentypBeschreibungBeispiel
INTEGERGanzzahl42, -7, 1000
DECIMAL(p,s) / NUMERICDezimalzahl19.99, 1234.56
TEXT / VARCHAR(n)Text’Hallo Welt’
BOOLEANWahrheitswertTRUE / FALSE
DATEDatum’2026-03-10’
TIMESTAMPDatum + Uhrzeit’2026-03-10 14:30:00’

Zahlendatentypen im Detail

CREATE TABLE artikel (
    id INTEGER PRIMARY KEY,               -- Ganzzahl
    name TEXT NOT NULL,                    -- Text
    preis DECIMAL(10, 2) NOT NULL,         -- Max 10 Stellen, davon 2 Nachkomma
    gewicht_kg DECIMAL(5, 3),              -- z.B. 1.250
    menge INTEGER DEFAULT 0,              -- Ganzzahl mit Standardwert
    aktiv BOOLEAN DEFAULT TRUE            -- Wahr/Falsch
);

Text-Datentypen

CREATE TABLE nachrichten (
    id INTEGER PRIMARY KEY,
    betreff VARCHAR(200) NOT NULL,    -- Max 200 Zeichen
    inhalt TEXT,                       -- Beliebig langer Text
    absender VARCHAR(100) NOT NULL
);
TypBeschreibung
VARCHAR(n)Text mit maximaler Laenge n
CHAR(n)Text mit fester Laenge n (mit Leerzeichen aufgefuellt)
TEXTText ohne Laengenbeschraenkung

Datums-Datentypen

CREATE TABLE ereignisse (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    datum DATE NOT NULL,                           -- Nur Datum
    zeitpunkt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Datum + Uhrzeit
    dauer INTEGER                                  -- Dauer in Minuten
);

Einschraenkungen (Constraints)

Constraints definieren Regeln fuer die Daten in deinen Spalten:

NOT NULL - Wert erforderlich

CREATE TABLE mitarbeiter (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,       -- Name muss angegeben werden
    email TEXT,               -- Email ist optional (darf NULL sein)
    abteilung TEXT NOT NULL   -- Abteilung muss angegeben werden
);

UNIQUE - Eindeutiger Wert

CREATE TABLE benutzer (
    id INTEGER PRIMARY KEY,
    benutzername TEXT UNIQUE NOT NULL,  -- Muss eindeutig sein
    email TEXT UNIQUE NOT NULL          -- Muss eindeutig sein
);

DEFAULT - Standardwert

CREATE TABLE aufgaben (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    status TEXT DEFAULT 'offen',
    prioritaet INTEGER DEFAULT 3,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Beim INSERT werden Standardwerte automatisch gesetzt:
INSERT INTO aufgaben (id, titel) VALUES (1, 'Einkaufen');
-- status = 'offen', prioritaet = 3, erstellt_am = jetzt

CHECK - Wertebedingung

CREATE TABLE produkte_v2 (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    preis DECIMAL(10,2) CHECK (preis > 0),            -- Preis muss positiv sein
    rabatt DECIMAL(3,2) CHECK (rabatt >= 0 AND rabatt <= 1),  -- 0 bis 1
    lagerbestand INTEGER CHECK (lagerbestand >= 0)     -- Nicht negativ
);

PRIMARY KEY - Primaerschluessel

Einfacher Primaerschluessel

CREATE TABLE kategorien (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL UNIQUE
);

Zusammengesetzter Primaerschluessel

-- Primaerschluessel aus mehreren Spalten
CREATE TABLE kurs_teilnahme (
    kurs_id INTEGER,
    teilnehmer_id INTEGER,
    anmeldedatum DATE DEFAULT CURRENT_DATE,
    PRIMARY KEY (kurs_id, teilnehmer_id)
);

Auto-Increment

-- PostgreSQL: SERIAL
CREATE TABLE blog_posts (
    id SERIAL PRIMARY KEY,
    titel TEXT NOT NULL,
    inhalt TEXT
);

-- PostgreSQL (modern): GENERATED ALWAYS
CREATE TABLE blog_posts_v2 (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    titel TEXT NOT NULL,
    inhalt TEXT
);

-- SQLite: INTEGER PRIMARY KEY ist automatisch auto-increment
CREATE TABLE blog_posts (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    inhalt TEXT
);

FOREIGN KEY - Fremdschluessel

Fremdschluessel verknuepfen Tabellen miteinander:

CREATE TABLE autoren (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE buecher (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    autor_id INTEGER,
    FOREIGN KEY (autor_id) REFERENCES autoren(id)
);

Oder die kuerzere Schreibweise:

CREATE TABLE buecher (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    autor_id INTEGER REFERENCES autoren(id)
);

Fremdschluessel mit Aktionen

CREATE TABLE kommentare (
    id INTEGER PRIMARY KEY,
    beitrag_id INTEGER REFERENCES blog_posts(id) ON DELETE CASCADE,
    autor TEXT NOT NULL,
    text TEXT NOT NULL,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Wenn ein Blog-Post geloescht wird, werden seine Kommentare automatisch mitgeloescht

Tabelle nur erstellen, wenn sie nicht existiert

-- Fehler, wenn die Tabelle schon existiert:
CREATE TABLE kunden (id INTEGER PRIMARY KEY);

-- Kein Fehler, wenn die Tabelle schon existiert:
CREATE IF NOT EXISTS TABLE kunden (id INTEGER PRIMARY KEY);

-- Korrekte Syntax:
CREATE TABLE IF NOT EXISTS kunden (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL
);

DROP TABLE - Tabelle loeschen

-- Tabelle loeschen (Fehler, wenn sie nicht existiert)
DROP TABLE alte_tabelle;

-- Tabelle loeschen, wenn sie existiert
DROP TABLE IF EXISTS alte_tabelle;

Vorsicht: DROP TABLE loescht die Tabelle und alle Daten unwiderruflich!

Temporaere Tabellen

Temporaere Tabellen existieren nur fuer die aktuelle Sitzung:

CREATE TEMPORARY TABLE temp_berechnung (
    produkt_id INTEGER,
    neuer_preis DECIMAL(10,2)
);

-- Daten einfuegen und verwenden
INSERT INTO temp_berechnung
SELECT id, preis * 1.1 FROM produkte;

-- Die Tabelle verschwindet automatisch am Ende der Sitzung

Praxisbeispiel: Blog-System entwerfen

-- Benutzer
CREATE TABLE benutzer (
    id INTEGER PRIMARY KEY,
    benutzername VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    passwort_hash TEXT NOT NULL,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Blog-Beitraege
CREATE TABLE beitraege (
    id INTEGER PRIMARY KEY,
    titel VARCHAR(200) NOT NULL,
    inhalt TEXT NOT NULL,
    autor_id INTEGER NOT NULL REFERENCES benutzer(id),
    veroeffentlicht BOOLEAN DEFAULT FALSE,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Kommentare
CREATE TABLE kommentare (
    id INTEGER PRIMARY KEY,
    beitrag_id INTEGER NOT NULL REFERENCES beitraege(id) ON DELETE CASCADE,
    autor_id INTEGER NOT NULL REFERENCES benutzer(id),
    text TEXT NOT NULL,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Tags
CREATE TABLE tags (
    id INTEGER PRIMARY KEY,
    name VARCHAR(50) UNIQUE NOT NULL
);

-- Beitrag-Tag Zuordnung (N:M)
CREATE TABLE beitrag_tags (
    beitrag_id INTEGER REFERENCES beitraege(id) ON DELETE CASCADE,
    tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE,
    PRIMARY KEY (beitrag_id, tag_id)
);

Was kommt als Naechstes?

Im naechsten Tutorial gehen wir tiefer auf SQL-Datentypen ein und lernst du die Unterschiede zwischen PostgreSQL und SQLite.

Zusammenfassung

  • CREATE TABLE erstellt neue Tabellen mit definierten Spalten
  • Jede Spalte hat einen Datentyp (INTEGER, TEXT, DECIMAL, DATE, …)
  • Constraints schuetzen die Datenqualitaet (NOT NULL, UNIQUE, CHECK)
  • PRIMARY KEY identifiziert Datensaetze eindeutig
  • FOREIGN KEY verknuepft Tabellen und erzwingt referentielle Integritaet
  • IF NOT EXISTS verhindert Fehler bei bestehenden Tabellen
  • DROP TABLE loescht eine Tabelle unwiderruflich

Uebungen

  1. Einfach: Erstelle eine Tabelle notizen mit den Spalten id, titel (Pflichtfeld), inhalt und erstellt_am.
  2. Constraints: Erstelle eine Tabelle mitarbeiter mit id, name (Pflicht), email (eindeutig), gehalt (muss positiv sein) und abteilung.
  3. Fremdschluessel: Erstelle zwei Tabellen kurse und teilnehmer mit einer Zwischentabelle kurs_anmeldung.
  4. Blog-System: Ergaenze das Blog-System um eine Tabelle likes (ein Benutzer kann einen Beitrag einmal liken).
  5. Design: Entwirf ein Tabellenschema fuer eine einfache To-Do-App mit Benutzern, Listen und Aufgaben.
-- Loesung zu Uebung 1:
CREATE TABLE notizen (
    id INTEGER PRIMARY KEY,
    titel TEXT NOT NULL,
    inhalt TEXT,
    erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Pro-Tipp: Plane deine Tabellenstruktur auf Papier oder in einem Diagramm, bevor du CREATE TABLE schreibst. Ueberlege dir: Welche Tabellen brauche ich? Welche Beziehungen bestehen? Welche Spalten sind Pflichtfelder? Ein gutes Schema spart spaeter viel Aerger mit Dateninkonsistenzen.

Zurück zum SQL Kurs