SQL Datentypen
Alle wichtigen SQL-Datentypen im Überblick: Zahlen, Text, Datum, Boolean und mehr - mit Unterschieden zwischen PostgreSQL und SQLite.
Die richtige Wahl des Datentyps ist entscheidend fuer Speicherplatz, Performance und Datenqualitaet. In diesem Tutorial lernst du alle wichtigen SQL-Datentypen kennen und wann du welchen verwenden solltest.
Warum sind Datentypen wichtig?
Stell dir vor, du speicherst Preise als Text. Was passiert dann?
-- Text-Sortierung: '9.99' kommt NACH '10.00' (alphabetisch!)
-- Zahlen-Sortierung: 9.99 kommt VOR 10.00 (mathematisch korrekt)
Der richtige Datentyp sorgt fuer:
- Korrekte Sortierung und Berechnungen
- Datenvalidierung (keine Buchstaben in Zahlenspalten)
- Effizienten Speicherplatz
- Bessere Performance bei Abfragen
Ganzzahlen (Integer)
| Typ | Speicher | Wertebereich | Verwendung |
|---|---|---|---|
SMALLINT | 2 Byte | -32.768 bis 32.767 | Kleine Zahlen (Alter, Menge) |
INTEGER / INT | 4 Byte | -2,1 Mrd. bis 2,1 Mrd. | Standard fuer IDs, Mengen |
BIGINT | 8 Byte | Sehr grosse Zahlen | Grosse IDs, Zaehlwerte |
CREATE TABLE lager (
id INTEGER PRIMARY KEY,
regal_nr SMALLINT NOT NULL,
artikel_id INTEGER NOT NULL,
menge INTEGER DEFAULT 0,
gesamtverkauf BIGINT DEFAULT 0
);
Auto-Increment Typen
-- PostgreSQL:
CREATE TABLE benutzer (
id SERIAL PRIMARY KEY, -- Auto-Increment INTEGER
name TEXT NOT NULL
);
-- Oder moderner:
CREATE TABLE benutzer (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL
);
-- SQLite: INTEGER PRIMARY KEY ist automatisch auto-increment
CREATE TABLE benutzer (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
Dezimalzahlen
| Typ | Beschreibung | Genauigkeit | Verwendung |
|---|---|---|---|
DECIMAL(p,s) / NUMERIC(p,s) | Exakte Dezimalzahl | Exakt | Geld, Preise |
REAL / FLOAT | Gleitkommazahl | Ungefaehr | Wissenschaft, Messungen |
DOUBLE PRECISION | Doppelte Genauigkeit | Ungefaehr | Berechnungen |
-- DECIMAL(10,2) = maximal 10 Stellen, davon 2 Nachkomma
-- Beispiele: 12345678.99, 0.01, 99999999.99
CREATE TABLE finanzen (
id INTEGER PRIMARY KEY,
betrag DECIMAL(10,2) NOT NULL, -- Exakt: fuer Geldbetraege
zinssatz DECIMAL(5,4), -- z.B. 0.0375 (3,75%)
steuersatz DECIMAL(4,3) -- z.B. 0.190 (19%)
);
Wichtig: Verwende fuer Geldbetraege IMMER DECIMAL / NUMERIC, niemals FLOAT!
-- FLOAT ist ungenau bei Geldbetraegen:
SELECT CAST(0.1 AS FLOAT) + CAST(0.2 AS FLOAT);
-- Ergebnis koennte 0.30000000000000004 sein!
-- DECIMAL ist exakt:
SELECT CAST(0.1 AS DECIMAL(3,1)) + CAST(0.2 AS DECIMAL(3,1));
-- Ergebnis: 0.3 (genau)
Text-Datentypen
| Typ | Beschreibung | Verwendung |
|---|---|---|
VARCHAR(n) | Text mit max. n Zeichen | Namen, E-Mails |
CHAR(n) | Text mit genau n Zeichen | Laendercodes, PLZ |
TEXT | Unbegrenzter Text | Beschreibungen, Artikel |
CREATE TABLE adressen (
id INTEGER PRIMARY KEY,
strasse VARCHAR(200) NOT NULL,
hausnummer VARCHAR(10) NOT NULL,
plz CHAR(5) NOT NULL, -- Immer 5 Zeichen
stadt VARCHAR(100) NOT NULL,
land CHAR(2) DEFAULT 'DE' -- Immer 2 Zeichen (ISO-Code)
);
VARCHAR vs. TEXT
| VARCHAR(n) | TEXT | |
|---|---|---|
| Laengenbegrenzung | Ja (max n Zeichen) | Nein |
| Validierung | Fehler bei zu langem Text | Alles erlaubt |
| Performance | Gleich (in PostgreSQL) | Gleich (in PostgreSQL) |
| Empfehlung | Wenn Laenge bekannt | Wenn Laenge variabel |
In PostgreSQL gibt es performance-maessig keinen Unterschied. VARCHAR(n) dient hauptsaechlich der Dokumentation und Validierung.
Datum und Zeit
| Typ | Speichert | Format | Beispiel |
|---|---|---|---|
DATE | Nur Datum | YYYY-MM-DD | ’2026-03-10’ |
TIME | Nur Uhrzeit | HH:MM:SS | ’14:30:00’ |
TIMESTAMP | Datum + Uhrzeit | YYYY-MM-DD HH:MM:SS | ’2026-03-10 14:30:00’ |
INTERVAL | Zeitdauer (PostgreSQL) | Verschiedene | ’3 days’, ‘2 hours’ |
CREATE TABLE termine (
id INTEGER PRIMARY KEY,
titel TEXT NOT NULL,
datum DATE NOT NULL,
uhrzeit TIME,
erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Beispiel-Daten
INSERT INTO termine (id, titel, datum, uhrzeit)
VALUES (1, 'Meeting', '2026-03-15', '10:00:00');
Datum-Berechnungen
-- PostgreSQL:
SELECT
datum,
datum + INTERVAL '7 days' AS naechste_woche,
datum - INTERVAL '1 month' AS letzter_monat,
CURRENT_DATE - datum AS tage_bis_termin
FROM termine;
-- SQLite:
SELECT
datum,
date(datum, '+7 days') AS naechste_woche,
date(datum, '-1 month') AS letzter_monat,
julianday(datum) - julianday('now') AS tage_bis_termin
FROM termine;
Boolean
-- PostgreSQL: Echter Boolean-Typ
CREATE TABLE einstellungen (
id INTEGER PRIMARY KEY,
benachrichtigungen BOOLEAN DEFAULT TRUE,
newsletter BOOLEAN DEFAULT FALSE,
premium BOOLEAN DEFAULT FALSE
);
INSERT INTO einstellungen (id, benachrichtigungen, newsletter, premium)
VALUES (1, TRUE, FALSE, TRUE);
SELECT * FROM einstellungen WHERE premium = TRUE;
-- SQLite: Kein nativer Boolean, nutzt INTEGER (0 = false, 1 = true)
CREATE TABLE einstellungen (
id INTEGER PRIMARY KEY,
benachrichtigungen INTEGER DEFAULT 1,
newsletter INTEGER DEFAULT 0,
premium INTEGER DEFAULT 0
);
JSON (PostgreSQL)
PostgreSQL unterstuetzt JSON-Daten nativ:
-- PostgreSQL:
CREATE TABLE events (
id INTEGER PRIMARY KEY,
typ TEXT NOT NULL,
daten JSONB NOT NULL, -- JSONB = Binary JSON (schneller)
erstellt_am TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO events (id, typ, daten) VALUES
(1, 'klick', '{"seite": "/produkte", "button": "kaufen"}');
-- JSON-Felder abfragen
SELECT daten->>'seite' AS seite
FROM events
WHERE daten->>'button' = 'kaufen';
Datentyp-Vergleich: PostgreSQL vs. SQLite
| Zweck | PostgreSQL | SQLite |
|---|---|---|
| Ganzzahl | INTEGER, BIGINT | INTEGER |
| Dezimalzahl | DECIMAL, NUMERIC | REAL |
| Text | VARCHAR, TEXT | TEXT |
| Boolean | BOOLEAN | INTEGER (0/1) |
| Datum | DATE, TIMESTAMP | TEXT (als ISO-String) |
| JSON | JSON, JSONB | TEXT |
| Binaerdaten | BYTEA | BLOB |
SQLite hat ein sehr flexibles Typsystem. Es speichert intern nur 5 Typen: NULL, INTEGER, REAL, TEXT, BLOB. Andere Typnamen werden automatisch zugeordnet.
Den richtigen Datentyp waehlen
Entscheidungshilfe
| Daten | Empfohlener Typ | Grund |
|---|---|---|
| IDs | INTEGER / SERIAL | Eindeutig, schnell |
| Preise / Geld | DECIMAL(10,2) | Exakte Berechnung |
| Namen | VARCHAR(100) | Laengenbegrenzung |
| E-Mails | VARCHAR(255) | Standard-Maximallaenge |
| Beschreibungen | TEXT | Variable Laenge |
| Ja/Nein | BOOLEAN | Klar und eindeutig |
| Geburtstag | DATE | Nur Datum noetig |
| Erstellungszeit | TIMESTAMP | Datum + Uhrzeit |
| PLZ (DE) | CHAR(5) | Immer 5 Zeichen |
| Laendercode | CHAR(2) | ISO-Standard |
Was kommt als Naechstes?
Im naechsten Tutorial lernst du Constraints und Schluessel im Detail kennen - damit sicherst du die Qualitaet deiner Daten ab.
Zusammenfassung
- INTEGER fuer Ganzzahlen, DECIMAL fuer exakte Dezimalzahlen (Geld!)
- VARCHAR(n) fuer Text mit bekannter Maximallaenge, TEXT fuer unbegrenzten Text
- DATE fuer Datum, TIMESTAMP fuer Datum + Uhrzeit
- Verwende niemals FLOAT/REAL fuer Geldbetraege
- PostgreSQL hat mehr Datentypen (JSON, Arrays, etc.) als SQLite
- Der richtige Datentyp schuetzt vor Fehlern und verbessert die Performance
Uebungen
- Entscheidung: Welchen Datentyp wuerdest du fuer diese Spalten waehlen: Alter, Gewicht (in kg), Telefonnummer, Geburtsdatum, Kontostand?
- Tabelle erstellen: Erstelle eine Tabelle
rezeptemit sinnvollen Datentypen fuer: Titel, Beschreibung, Zubereitungszeit in Minuten, Schwierigkeit (1-5), vegetarisch (ja/nein), Erstelldatum. - Fehler finden: Was ist an dieser Tabelle falsch?
CREATE TABLE rechnungen ( id TEXT PRIMARY KEY, betrag FLOAT, datum VARCHAR(50) ); - PostgreSQL JSON: Erstelle eine Tabelle fuer Benutzereinstellungen, die flexible JSON-Daten speichern kann.
-- Loesung zu Uebung 2:
CREATE TABLE rezepte (
id INTEGER PRIMARY KEY,
titel VARCHAR(200) NOT NULL,
beschreibung TEXT,
zubereitungszeit INTEGER NOT NULL,
schwierigkeit SMALLINT CHECK (schwierigkeit BETWEEN 1 AND 5),
vegetarisch BOOLEAN DEFAULT FALSE,
erstellt_am DATE DEFAULT CURRENT_DATE
);
Pro-Tipp: Im Zweifel waehle den spezifischeren Datentyp. Eine Telefonnummer sollte TEXT sein (wegen fuehrender Nullen und +49), nicht INTEGER. Ein Datum sollte DATE sein, nicht TEXT. Je spezifischer der Datentyp, desto besser kann die Datenbank deine Daten schuetzen und optimieren.