mitmario.dev

Warum eine Datenbank

Python Sandbox 5 Min Lesezeit 4 BeispieleLektion 1 von 6

In Mias Laden pflegen zwei Programme dieselbe bestand.csv, und am Ende des Tages fehlt ein Verkauf. Die Daten in diesem Kurs liegen bisher in Dateien. Das Haushaltsbuch steht in ausgaben.txt, die Mitglieder eines Vereins in einer CSV, die Einstellungen in JSON. Das passt, solange ein Programm die Datei liest, etwas damit macht und sie danach ganz schreibt. Wo das nicht mehr reicht, kommt eine Datenbank.

Für die Sprache SQL selbst steht auf der Plattform ein eigener Kurs im Fahrplan. Hier geht es darum, wie Python mit einer Datenbank redet.

Wer zuletzt schreibt, gewinnt

Wer zuletzt schreibt, gewinnt
from pathlib import Path

datei = Path("bestand.csv")
datei.write_text("Brot;12\nButter;8\nMilch;30\n", encoding="utf-8")

# Zwei Programme lesen den Bestand zur selben Zeit: die Kasse und das Lager.
kasse = datei.read_text(encoding="utf-8")
lager = datei.read_text(encoding="utf-8")

# Die Kasse verkauft drei Stück Butter, das Lager bucht eine Lieferung Milch.
datei.write_text(kasse.replace("Butter;8", "Butter;5"), encoding="utf-8")
datei.write_text(lager.replace("Milch;30", "Milch;54"), encoding="utf-8")

print(datei.read_text(encoding="utf-8"), end="")

Die beiden Programme sind die Kasse, die jeden Verkauf abzieht, und das Lager, das jede Lieferung dazuzählt. Beide machen es wie in Lektion 12.5. Datei lesen, ändern, ganz zurückschreiben.

Laufen sie zur selben Zeit, lesen beide denselben Stand. Die Kasse schreibt ihren zurück, mit 5 Stück Butter. Gleich danach schreibt das Lager seinen, und da steht die Butter noch bei 8. Am Ende ist der Verkauf weg. Es gibt keine Fehlermeldung, und keines der beiden Programme hat etwas falsch gemacht.

Wenn du schon mal zu zweit an einer Tabelle gearbeitet hast, die per Mail hin- und herging, kennst du das. Wer zuletzt speichert, gewinnt. Deshalb sperrt Excel eine Datei auf einem Netzlaufwerk, solange jemand sie offen hat.

Zwei Dinge kommen noch dazu, und die fangen nicht erst bei zwei Programmen an. Jede Frage an eine CSV ist eine Schleife über die ganze Datei. Bei einem Haushaltsbuch, das seit Jahren wächst, sind das bei jeder Frage alle Jahre. Und jede Änderung schreibt die ganze Datei neu. Stürzt das Programm dabei ab, liegt danach eine halbe Datei da.

Eine Datei, die man fragt

Mit einer Datenbank (database) fällt diese Arbeit weg. Man liest sie nicht, man fragt sie. Welche Artikel liegen unter fünf Stück? Was ist im September für Lebensmittel draufgegangen? Die Datenbank sucht selbst und gibt nur zurück, was passt.

Wenn zwei Programme zur selben Zeit etwas ändern, ändert jedes nur seine Zeilen, statt die ganze Datei zurückzuschreiben. Geschrieben wird nacheinander, und eine halbe Datei bleibt nie zurück. Eine Lieferung im Lager überschreibt dann keinen Verkauf an der Kasse mehr.

Die meisten Datenbanken sind eigene Programme, die auf einem Server laufen, PostgreSQL oder MySQL zum Beispiel. Mit denen verbindet man sich über das Netz, mit Name und Passwort, und jemand muss sie einrichten und pflegen.

Bei SQLite steckt die ganze Datenbank in einer einzigen Datei. Gelesen und geschrieben wird sie mit einem Modul, das mit Python kommt, sqlite3. Es gibt nichts zu installieren und nichts einzurichten, und kopieren lässt sich die Datenbank wie jede andere Datei. SQLite steckt in jedem Smartphone und in den meisten Browsern, und für ein eigenes Werkzeug reicht es lange.

Tabelle, Zeile, Spalte

Die erste Tabelle
import sqlite3

verbindung = sqlite3.connect("laden.db")
verbindung.execute("CREATE TABLE artikel (name TEXT, preis INTEGER, bestand INTEGER)")
verbindung.close()
print("laden.db hat jetzt eine Tabelle artikel")

Eine Datenbank besteht aus Tabellen (table), so wie eine Excel-Mappe aus Blättern. Eine Tabelle hat Spalten (column) mit Namen, und jeder Eintrag ist eine Zeile (row), wie eine Zeile in einer CSV. Anders als bei einer CSV legt man die Spalten aber vorher fest, einmal, mit ihrem Namen und der Art von Wert, die hineingehört.

sqlite3.connect("laden.db") öffnet eine Verbindung (connection) zur Datei laden.db. Gibt es die Datei noch nicht, legt connect sie an. Mit execute (ausführen) geht ein Befehl an die Datenbank.

Dieser Befehl ist nicht in Python geschrieben, sondern in SQL (Structured Query Language), einer eigenen kleinen Sprache nur für Datenbanken. Python reicht ihn als Text weiter, deshalb steht er in Anführungszeichen. CREATE TABLE artikel legt eine Tabelle mit dem Namen artikel an. In den Klammern stehen die Spalten mit ihrer Art, durch Kommas getrennt.

Die Großbuchstaben sind Gewohnheit und keine Pflicht. Man sieht daran, was zu SQL gehört und was ein selbst gewählter Name ist. Am Ende schließt close() die Verbindung, wie bei einer Datei.

Was in laden.db steht, kannst du dir über die Befehlsleiste ansehen. sqlite3 gibt es nämlich auch als Programm für das Terminal, und dort nennt .tables die Tabellen und .schema den Befehl, mit dem sie angelegt wurden. Auf dem Mac ist das Programm schon da, unter Windows und vielen Linux-Systemen muss man es erst installieren. Mit cat sähe man in laden.db übrigens vor allem Zeichensalat, denn eine Datenbank ist keine Textdatei.

Welche Art von Wert

SQLite kennt nur wenige Arten von Werten. Für ein Haushaltsbuch reichen drei davon, INTEGER für ganze Zahlen, REAL für Kommazahlen und TEXT für Text. Zwei Dinge fehlen aber, die in jedem Haushaltsbuch vorkommen.

Ein Datum gibt es nicht als eigene Art. Es steht als Text in der Tabelle, und zwar in der Form 2026-09-03, mit dem Jahr zuerst. Das ist keine Geschmackssache. Text wird Zeichen für Zeichen verglichen, und nur wenn das Jahr vorn steht, liegt 2026-09-03 vor 2026-10-01. In der Form 03.09.2026 käme der 1. Oktober vor dem 3. September, die Falle aus Lektion 8.7. Aus einem date macht isoformat() diese Form: date(2026, 9, 3).isoformat() gibt '2026-09-03'.

Und Geld gibt es nicht als Decimal. REAL ist dieselbe Kommazahl wie float in Python, samt 0.30000000000000004. Beträge stehen deshalb als ganze Zahlen in Cent in der Tabelle, 2,49 Euro also als 249, so wie schon in Abschnitt 2. Ganze Zahlen rechnen genau, auch beim Zusammenzählen. In Euro umgerechnet wird erst, wenn der Betrag im Terminal erscheint.

Ein zweiter Start

Ein zweiter Start
import sqlite3


def anlegen():
    verbindung = sqlite3.connect("laden.db")
    verbindung.execute("CREATE TABLE artikel (name TEXT, preis INTEGER, bestand INTEGER)")
    verbindung.close()
    print("Tabelle angelegt")


anlegen()  # heute
anlegen()  # morgen, laden.db liegt dann noch da

Ein Programm, das eine Datenbank anlegt, läuft selten nur einmal. Im Beispiel wird anlegen() zweimal aufgerufen, so als würdest du dasselbe Programm heute starten und morgen wieder. Beim ersten Aufruf wird die Tabelle angelegt. Der zweite trifft auf die Datei vom ersten, in der die Tabelle schon steht, und endet mit sqlite3.OperationalError: table artikel already exists. Die Tabelle gibt es also schon.

Dasselbe passiert mit dem Beispiel davor, wenn du es im Terminal mit python main.py noch einmal startest. Im Terminal räumt niemand auf, laden.db bleibt liegen, genau wie auf deinem eigenen Rechner.

Nur, wenn sie fehlt

Nur, wenn sie fehlt
import sqlite3


def anlegen():
    verbindung = sqlite3.connect("laden.db")
    verbindung.execute("CREATE TABLE IF NOT EXISTS artikel (name TEXT, preis INTEGER, bestand INTEGER)")
    verbindung.close()
    print("Die Tabelle artikel ist da")


anlegen()  # heute
anlegen()  # morgen, laden.db liegt dann noch da

CREATE TABLE IF NOT EXISTS legt die Tabelle nur an, wenn es sie noch nicht gibt. Sonst passiert nichts, auch kein Fehler. Was in der Tabelle steht, bleibt, wie es ist. Diese Zeile steht deshalb am Anfang fast jedes Programms, das mit einer Datenbank arbeitet.

Man könnte auch auf die Idee kommen, die Datei am Anfang zu löschen oder die Tabelle wegzuwerfen und neu anzulegen. Dann läuft das Programm zwar jedes Mal durch, nimmt aber jedes Mal alles mit, was darin stand. Für ein Beispiel, das jedes Mal frisch anfangen soll, ist das in Ordnung. Für ein Haushaltsbuch wäre es das Ende.

Was die Aufgabe will

Das Haushaltsbuch zieht in eine Datenbank um. Dort braucht es zuerst eine Tabelle, die auch den zweiten Start übersteht. Die eigentliche Entscheidung ist, welche Art von Wert in welche Spalte gehört. In der nächsten Lektion kommen die Ausgaben hinein, danach die Fragen.

Zum Mitnehmen

SQLite legt alles in eine Datei, die man fragt, statt sie zu lesen, und in Python steckt es als Modul sqlite3. connect() öffnet die Datei oder legt sie neu an, execute() schickt einen Befehl in SQL, und dank IF NOT EXISTS klappt das Anlegen auch beim zweiten Start. Datumsangaben stehen als Text wie 2026-09-03 darin, Geldbeträge als ganze Zahl in Cent.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.