0Pricing
Pandas & NumPy Academy · Lektion

DataFrames in Datenbanktabellen schreiben

Speichern Sie einen bereinigten DataFrame mit DataFrame.to_sql() in einer neuen oder bestehenden Tabelle und steuern Sie dabei if_exists und chunksize.

DataFrames in Datenbanktabellen schreiben ist eine kostenlose Pandas & NumPy Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Pandas & NumPy Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Pandas & NumPy Academy-Kurs umfasst insgesamt 4 Lektionen.

Warum DataFrames in Datenbanken schreiben?

Nachdem Sie Daten in Pandas bereinigt und transformiert haben, müssen Sie die Ergebnisse häufig dauerhaft wieder in einer Datenbank speichern: damit sie für andere Anwendungen, Dashboards oder Teammitglieder verfügbar sind, um inkrementelle Analyseergebnisse zu speichern oder um aus einem unverarbeiteten Data Lake einen Data Mart zu erstellen. DataFrame.to_sql() ist die standardmäßige Pandas-Methode, um Daten mit einem einzigen Aufruf in jede von SQLAlchemy unterstützte Datenbank zu schreiben.

Grundlegende Verwendung von to_sql()

df.to_sql('table_name', con=engine, if_exists='replace', index=False) schreibt den DataFrame in eine Datenbanktabelle. Der Parameter if_exists legt fest, was geschieht, wenn die Tabelle bereits vorhanden ist: 'fail' löst einen Fehler aus, 'replace' löscht die Tabelle und erstellt sie neu, und 'append' fügt neue Zeilen hinzu, ohne vorhandene zu verändern. Setzen Sie index=False grundsätzlich, außer Sie möchten den DataFrame-Index ausdrücklich als Spalte in der Datenbank speichern.

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///results.db')

df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=5),
    'revenue': [1200.0, 980.5, 1450.0, 760.3, 1100.0],
    'region': ['North', 'South', 'East', 'West', 'North']
})

df.to_sql('daily_revenue', con=engine,
          if_exists='replace', index=False)
print('Table written successfully')

Der Parameter if_exists erklärt

Die drei Werte von if_exists dienen unterschiedlichen Anwendungsfällen. 'replace' ist für die Entwicklung gedacht: Löschen Sie die alte Tabelle und erstellen Sie eine neue — Schemaänderungen werden automatisch übernommen, aber alle alten Daten gehen verloren. 'append' ist für inkrementelle Ladevorgänge gedacht: Fügen Sie der vorhandenen Tabelle neue Zeilen hinzu, ohne ihre Struktur zu ändern — nützlich für tägliche Batch-Jobs. 'fail' dient als Sicherheitsvorkehrung: Verwenden Sie diesen Wert, um wichtige Tabellen davor zu schützen, versehentlich durch eine fehlerhafte Pipeline überschrieben zu werden.

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///results.db')

new_batch = pd.DataFrame({
    'date': ['2024-06-01', '2024-06-02'],
    'revenue': [1500.0, 1300.0],
    'region': ['North', 'East']
})

# Append new rows without losing existing data
new_batch.to_sql('daily_revenue', con=engine,
                 if_exists='append', index=False)
print('Appended new rows')

Spaltendatentypen steuern

Standardmäßig ordnet to_sql() Pandas-Datentypen automatisch SQLAlchemy-Typen zu. Manchmal sind die Standardwerte falsch — beispielsweise kann eine datetime64-Spalte in SQLite als TEXT gespeichert werden. Verwenden Sie den Parameter dtype, um exakte SQL-Typen mithilfe von SQLAlchemy-Typobjekten festzulegen. Dadurch werden die korrekte Speicherung, eine geeignete Indexierung und eine präzise Typbehandlung beim erneuten Einlesen der Daten sichergestellt. Überprüfen Sie das Schema nach dem Schreiben immer kurz mit PRAGMA table_info() oder inspector.get_columns().

import pandas as pd
import sqlalchemy as sa
from sqlalchemy import types

engine = sa.create_engine('sqlite:///results.db')

df = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Carol'],
    'score': [0.95, 0.87, 0.91],
    'created_at': pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03'])
})

df.to_sql('users', con=engine, if_exists='replace', index=False,
          dtype={'id': types.Integer(),
                 'score': types.Float(),
                 'created_at': types.DateTime()})

Schreiben in Blöcken mit chunksize

Bei großen DataFrames versucht to_sql() ohne chunksize, alle Zeilen in einer einzigen Anweisung einzufügen, was zu einem Datenbank-Timeout oder einem Speicherfehler führen kann. Geben Sie chunksize=N an, um N Zeilen pro Transaktion einzufügen. So kann die Datenbank schrittweise bestätigen, und der maximale Speicherbedarf wird reduziert. Eine Blockgröße von 10.000–50.000 Zeilen bietet typischerweise ein gutes Verhältnis zwischen Einfügegeschwindigkeit und Speicherverbrauch; der optimale Wert hängt jedoch von Ihrer Datenbank und der Netzwerklatenz ab.

import pandas as pd
import sqlalchemy as sa
import numpy as np

engine = sa.create_engine('sqlite:///results.db')

# Large DataFrame
df = pd.DataFrame({
    'id': range(500000),
    'value': np.random.randn(500000)
})

# Insert in chunks of 10,000 rows at a time
df.to_sql('large_table', con=engine,
          if_exists='replace',
          index=False,
          chunksize=10000)
print('Written 500,000 rows')

Upsert: Einfügen oder Aktualisieren

Das Pandas-to_sql() unterstützt Upsert (einfügen, wenn neu, aktualisieren, wenn vorhanden) nicht nativ. Verwenden Sie zur Implementierung eines Upserts SQLAlchemys Core mit einer INSERT OR REPLACE-Anweisung (SQLite) oder einer ON CONFLICT DO UPDATE-Anweisung (PostgreSQL). Eine gängige Behelfslösung in Pandas besteht darin, zunächst mit if_exists='replace' in eine temporäre Staging-Tabelle zu schreiben, anschließend mit rohem SQL die Staging-Tabelle in die produktive Tabelle zusammenzuführen und danach die Staging-Tabelle zu löschen.

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///results.db')

new_data = pd.DataFrame({
    'id': [1, 2, 5],
    'value': [99.9, 88.8, 77.7]
})

# Write to staging table
new_data.to_sql('staging', con=engine,
                if_exists='replace', index=False)

# Merge into production (SQLite syntax)
with engine.connect() as conn:
    conn.execute(sa.text(
        'INSERT OR REPLACE INTO production SELECT * FROM staging'
    ))
    conn.commit()
print('Upsert complete')

Das Schreiben überprüfen

Überprüfen Sie nach dem Schreiben immer das Ergebnis, indem Sie eine zusammenfassende Anzahl und die Zeilenanzahl erneut einlesen. Vergleichen Sie diese mit dem Quell-DataFrame. Dadurch werden unbemerkte Fehler erkannt, die durch nicht übereinstimmende Datentypen (z. B. NaN in einer Ganzzahlspalte, was zu teilweise ausgeführten Einfügungen führen kann) oder Datenbankbeschränkungen (z. B. Verstöße gegen eindeutige Schlüssel, durch die in manchen Konfigurationen Zeilen unbemerkt übersprungen werden) verursacht wurden. Ein schnelles SELECT COUNT(*) FROM table nach jedem to_sql-Aufruf verursacht nur minimalen zusätzlichen Aufwand und verhindert unbemerkten Datenverlust.

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///results.db')

df = pd.DataFrame({'id': range(1000), 'value': range(1000)})
df.to_sql('my_table', con=engine, if_exists='replace', index=False)

# Verify
with engine.connect() as conn:
    count = conn.execute(sa.text('SELECT COUNT(*) FROM my_table')).scalar()
print(f'Source rows: {len(df)}, DB rows: {count}')
assert count == len(df), 'Row count mismatch!'

Primärschlüssel nach dem Schreiben hinzufügen

to_sql() schreibt Daten, fügt jedoch keine Primärschlüssel oder Datenbankbeschränkungen hinzu — es erstellt eine einfache Tabelle. Fügen Sie bei einer produktiven Tabelle die Primärschlüsselbeschränkung separat mithilfe von rohem SQL hinzu, das über SQLAlchemy ausgeführt wird. SQLite erfordert eine Neuerstellung der Tabelle, um nach ihrer Erstellung Beschränkungen hinzuzufügen; PostgreSQL unterstützt dagegen ALTER TABLE ADD PRIMARY KEY. Alternativ können Sie das vollständige Schema im Voraus definieren und mit if_exists='append' Daten in eine bereits korrekt definierte Tabelle einfügen.

import pandas as pd
import sqlalchemy as sa
from sqlalchemy import Table, Column, Integer, Float, MetaData

engine = sa.create_engine('sqlite:///results.db')
meta = MetaData()

# Define table with primary key
my_table = Table('defined_table', meta,
    Column('id', Integer, primary_key=True),
    Column('value', Float)
)
meta.create_all(engine)  # Create table with constraints

# Then insert data using append
df = pd.DataFrame({'id': range(5), 'value': [1.1, 2.2, 3.3, 4.4, 5.5]})
df.to_sql('defined_table', con=engine,
          if_exists='append', index=False)

Transaktionales Schreiben

Für Datenkonsistenz sollten Sie to_sql() in eine explizite Transaktion einschließen. Wenn ein Schritt beim Schreiben in mehrere Tabellen fehlschlägt, können Sie alle Änderungen zurückrollen. Ohne Transaktion können teilweise ausgeführte Schreibvorgänge die Datenbank in einen inkonsistenten Zustand versetzen. Der Verbindungs-Kontextmanager von SQLAlchemy mit conn.begin() ermöglicht eine manuelle Transaktionssteuerung. Alternativ können Sie engine.begin() für einen automatisch bestätigten Block verwenden, der bei einer Ausnahme zurückgerollt wird.

import pandas as pd
import sqlalchemy as sa

engine = sa.create_engine('sqlite:///results.db')

df_orders = pd.DataFrame({'id': [1, 2], 'amount': [100.0, 200.0]})
df_summary = pd.DataFrame({'total': [300.0], 'count': [2]})

try:
    with engine.begin() as conn:  # Auto-rollback on exception
        df_orders.to_sql('orders_v2', con=conn,
                         if_exists='replace', index=False)
        df_summary.to_sql('summary_v2', con=conn,
                          if_exists='replace', index=False)
    print('Both tables written atomically')
except Exception as e:
    print(f'Write failed, rolled back: {e}')

Leistung: Methoden für Masseneinfügungen

Das standardmäßige to_sql() fügt pro SQL-Anweisung eine Zeile ein, was bei großen DataFrames sehr langsam ist. Übergeben Sie method='multi', um eine einzige INSERT-Anweisung mit mehreren Wertetupeln zu verwenden — in der Regel 10- bis 100-mal schneller. Für PostgreSQL können Sie eine benutzerdefinierte method-Funktion übergeben, die für den schnellstmöglichen Massenimport das COPY-Protokoll (über psycopg2s copy_expert) verwendet. Die optimale Methode hängt von Ihrer Datenbankversion und Ihrer Netzwerkkonfiguration ab.

import pandas as pd
import sqlalchemy as sa
import numpy as np
import time

engine = sa.create_engine('sqlite:///perf.db')
df = pd.DataFrame({'a': range(100000), 'b': np.random.randn(100000)})

# Default (one row per INSERT) — slow
start = time.time()
df.to_sql('test_default', con=engine, if_exists='replace', index=False)
print(f'Default: {time.time()-start:.2f}s')

# multi-row INSERT — faster
start = time.time()
df.to_sql('test_multi', con=engine, if_exists='replace',
          index=False, method='multi', chunksize=1000)
print(f'Multi: {time.time()-start:.2f}s')

Schreibvorgänge protokollieren und prüfen

Verfolgen Sie in Produktions-Pipelines, was wann geschrieben wurde, indem Sie eine Auditprotokolltabelle führen. Fügen Sie nach jedem erfolgreichen to_sql()-Aufruf eine Zeile mit dem Tabellennamen, der Zeilenanzahl, dem Zeitstempel und der ID der Pipelineausführung in das Auditprotokoll ein. So lassen sich fehlende Ausführungen, doppelte Schreibvorgänge oder Schemaänderungen im Zeitverlauf leicht erkennen. Das Auditprotokoll selbst ist ein über to_sql geschriebener Pandas-DataFrame — dieselbe Technik wird also rekursiv zur betrieblichen Überwachung eingesetzt.

import pandas as pd
import sqlalchemy as sa
from datetime import datetime

engine = sa.create_engine('sqlite:///results.db')

def write_with_audit(df, table_name, engine, run_id):
    df.to_sql(table_name, con=engine, if_exists='append', index=False)
    audit = pd.DataFrame([{
        'run_id': run_id,
        'table_name': table_name,
        'rows_written': len(df),
        'written_at': datetime.utcnow().isoformat()
    }])
    audit.to_sql('audit_log', con=engine, if_exists='append', index=False)
    print(f'Wrote {len(df)} rows to {table_name}')

df = pd.DataFrame({'id': [1, 2], 'val': [10, 20]})
write_with_audit(df, 'my_table', engine, run_id='run_001')

Schnelltest

Testen Sie Ihr Verständnis der Data-Analysis-Konzepte aus dieser Lektion.

Zusammenfassung der Lektion

In dieser Lektion haben Sie gelernt: df.to_sql() schreibt einen DataFrame in eine beliebige mit SQLAlchemy verbundene Datenbanktabelle, wobei der Parameter if_exists das Verhalten beim Erstellen, Anhängen oder Ersetzen steuert, chunksize und method='multi' verbessern die Leistung bei großen DataFrames, und transaktionale Schreibvorgänge mit engine.begin() stellen atomare Aktualisierungen über mehrere Tabellen sicher, die bei einem Fehler zurückgerollt werden. Als Nächstes vergleichen wir Pandas und SQL, um zu verstehen, wann welches Werkzeug die bessere Wahl ist.

Häufig gestellte Fragen

Ist die Lektion „DataFrames in Datenbanktabellen schreiben“ kostenlos?

Ja — der vollständige Text von „DataFrames in Datenbanktabellen schreiben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Pandas & NumPy Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Pandas & NumPy Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „DataFrames in Datenbanktabellen schreiben“?

Speichern Sie einen bereinigten DataFrame mit DataFrame.to_sql() in einer neuen oder bestehenden Tabelle und steuern Sie dabei if_exists und chunksize. Du übst Pandas & NumPy Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Pandas & NumPy Academy zu starten?

Keine Vorkenntnisse erforderlich. Pandas & NumPy Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „DataFrames in Datenbanktabellen schreiben“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Pandas & NumPy Academy-Lektion Code schreiben und ausführen?

Ja. Jede Pandas & NumPy Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Mit SQLAlchemy eine Datenbank verbinden
  2. SQL-Abfragen aus Pandas ausführen
  3. DataFrames in Datenbanktabellen schreiben
  4. Pandas vs. SQL: Das richtige Werkzeug wählen
← Zurück zu Pandas & NumPy Academy