Menu

SQLite ATTACH DATABASE: Mehrere DB-Dateien abfragen

Mit ATTACH DATABASE öffnest du mehrere SQLite-Dateien in einer Verbindung, fragst sie über Schema-Präfixe gemeinsam ab und trennst sie sauber wieder mit DETACH.

Diese Seite enthält ausführbare Editoren — bearbeiten, ausführen und Ausgabe sofort sehen.

Eine Verbindung, mehrere Dateien

Eine SQLite-Verbindung ist nicht an eine einzige Datei gebunden. Mit ATTACH DATABASE kannst du weitere .db-Dateien zusätzlich zur ursprünglich geöffneten einbinden und sie alle so abfragen, als wären sie Schemas innerhalb einer einzigen Datenbank. Das kommt dem Konzept "mehrere Datenbanken auf einem Server" in SQLite am nächsten.

Die Grundform sieht so aus:

Die Datei archive.db wird angelegt, falls sie noch nicht existiert – genau wie bei der Hauptdatenbank. Ab diesem Moment landet in dieser Session alles, was mit archive. beginnt, in der zweiten Datei. Alles mit dem Präfix main. (oder ganz ohne Präfix) bleibt in der ursprünglichen.

Jede Verbindung hat von Haus aus zwei implizite Schemas: main (die Datei, die du als Erstes geöffnet hast) und temp (ein Ablageraum für temporäre Tabellen). Mit ATTACH kommen weitere dazu.

Die Syntax und wofür der Alias gut ist

ATTACH DATABASE 'pfad/zu/datei.db' AS alias_name;

Der Alias ist der Schema-Name, mit dem du Tabellen qualifizierst. Er gilt nur für die aktuelle Verbindung – eine andere Verbindung, die dieselbe Datei attached, kann einen anderen Alias wählen. Nimm etwas Kurzes und Aussagekräftiges (archive, analytics, cache), denn du wirst es oft tippen.

Ein paar Dinge, die du wissen solltest:

  • Der Pfad ist relativ zum Arbeitsverzeichnis des Prozesses, sofern er nicht absolut ist.
  • Der String ':memory:' hängt unter dem Alias eine frische In-Memory-Datenbank an.
  • Der Alias darf nicht mit main oder temp kollidieren und sich auch nicht zwischen mehreren Attachments wiederholen.

SQLite Join über mehrere Datenbanken

Genau dafür greifen die meisten zu ATTACH. Sobald zwei Dateien in derselben Verbindung hängen, kannst du ihre Tabellen in einer einzigen Abfrage joinen – das ist die klassische SQLite Cross-Database-Query:

Der Query Planner behandelt beide Schemas genauso wie Tabellen in main. Indizes auf attachten Tabellen werden genutzt. EXPLAIN QUERY PLAN funktioniert auch über mehrere Datenbanken hinweg. Es gibt keinen Netzwerk-Roundtrip – beide Dateien sind im selben Prozess geöffnet.

Das ist wirklich praktisch, wenn du heiße Daten von kalten Archiven trennen willst, separate Dateien pro Mandant verwalten oder Referenzdaten aus einer schreibgeschützten Lookup-Datenbank ziehen möchtest.

SQLite Datenbank read-only und im Arbeitsspeicher attachen

Wenn die zweite Datenbank nur gelesen, aber nie verändert werden soll – etwa ein mitgeliefertes Referenz-Dataset – kannst du sie über eine URI schreibgeschützt attachen:

Damit das URI-Format funktioniert, muss die SQLite-Bibliothek mit aktiviertem SQLITE_OPEN_URI gebaut sein (in der CLI und in den meisten Sprach-Bindings ist das standardmäßig der Fall). Jedes INSERT, UPDATE oder DELETE auf ref.* schlägt dann mit einem Fehler fehl, bevor die Datei überhaupt angefasst wird.

Genauso praktisch sind In-Memory-Attachments, um Daten zwischenzulagern:

scratch verschwindet, sobald die Verbindung geschlossen wird. Verhält sich also wie temp, nur dass du die Lebensdauer selbst steuerst.

Transaktionen umfassen alle angehängten Datenbanken

Ein einzelnes BEGIN/COMMIT deckt Schreibvorgänge in main und in allen per ATTACH DATABASE angebundenen Schemas ab. Entweder werden alle Änderungen übernommen oder alle zurückgerollt — die Atomarität bleibt also auch über Dateigrenzen hinweg erhalten:

Das Verschieben von Zeilen aus einer aktiven Tabelle in eine Archivdatei ist genau der Anwendungsfall, bei dem du diese Garantie unbedingt brauchst. Ohne dateiübergreifende Atomarität würdest du nach einem Crash mitten im Vorgang entweder Duplikate haben oder – noch schlimmer – Zeilen verlieren.

Ein wichtiger Hinweis: Sobald innerhalb einer Transaktion in mehrere angehängte Datenbanken geschrieben wird, schaltet SQLite auf ein vorsichtigeres Commit-Protokoll um, das ein temporäres Journal benötigt. Das ist langsamer als ein Commit auf einer einzelnen Datei, aber genauso sicher.

Datenbank wieder lösen mit DETACH

Wenn du die angehängte Datenbank nicht mehr brauchst, hängst du sie einfach wieder ab:

DETACH DATABASE archive;

Die Datei auf der Platte bleibt unangetastet — DETACH schließt lediglich das Handle in der aktuellen Verbindung. Zwei Einschränkungen sollte man im Hinterkopf behalten:

  • main und temp lassen sich nicht detachen.
  • Eine Datenbank, die gerade in einer Transaktion steckt oder offene Statements hat, kannst du ebenfalls nicht detachen.

Falls du das Detachen vergisst, ist das kein Drama: Sobald die Verbindung geschlossen wird, räumt SQLite ohnehin alles auf.

Limits und typische Fehler bei SQLite Attach Database

Ein paar praktische Grenzen, die du kennen solltest:

  • Standardmäßig sind 10 angehängte Datenbanken pro Verbindung erlaubt (zusätzlich zu main und temp). Das Compile-Time-Maximum liegt bei 125. Wer das Limit reißt, bekommt too many attached databases - max 10 zu sehen.
  • Jede angehängte Datei belegt einen eigenen Page Cache. Ein Dutzend große Datenbanken parallel anzuhängen ist nicht gratis — der RAM-Verbrauch steigt spürbar.
  • ATTACH selbst läuft nicht innerhalb einer Transaktion. Setz das Statement also vor BEGIN ab oder erst nach COMMIT.

Ein paar Fehler, die dir früher oder später begegnen werden:

-- Die Datei existiert nicht und das Verzeichnis ist nicht beschreibbar:
Error: unable to open database: 'missing/path.db'

-- Du hast versucht, in ein schreibgeschütztes Attachment zu schreiben:
Error: attempt to write a readonly database

-- Du hast denselben Alias zweimal verwendet:
Error: database archive is already in use

Die meisten dieser Fehler erklären sich von selbst, wenn man sie einmal liest. Stolperstein ist meist der „already in use"-Fehler: ATTACH überschreibt einen vorhandenen Alias nicht – du musst vorher explizit DETACH aufrufen.

Ein Praxisbeispiel: Hot/Cold-Split

Zum Abschluss alles zusammen – ein kleiner Archivierungs-Workflow, der Bestellungen, die älter als ein Jahr sind, aus der Hauptdatenbank in ein Archiv verschiebt:

Alte Zeilen wandern in archive.orders, die aktuellen bleiben in main. Reports, die Historie brauchen, können über beide Datenbanken hinweg joinen – während die täglichen Queries auf main.orders schnell bleiben, weil die Tabelle kleiner ist. Eine Verbindung, zwei Dateien, eine Transaktion.

Als Nächstes: Prepared Statements

Bei ATTACH geht es darum, einer einzelnen Verbindung Zugriff auf mehr Daten zu geben. Die nächsten Themen drehen sich darum, wie Anwendungen sicher und effizient mit SQLite kommunizieren – los geht's mit Prepared Statements, der Grundlage für Parameter-Bindings und SQL-Injection-sichere Queries.

Häufig gestellte Fragen

Was macht ATTACH DATABASE in SQLite genau?

ATTACH DATABASE 'file.db' AS alias hängt eine zweite SQLite-Datei an deine aktuelle Verbindung an und gibt ihr einen Schemanamen. Danach sprichst du die Tabellen darin als alias.table_name an und kannst sie in einer einzigen Query mit Tabellen aus deiner Hauptdatenbank joinen.

Wie viele Datenbanken kann SQLite gleichzeitig attachen?

Standardmäßig erlaubt SQLite bis zu 10 angehängte Datenbanken pro Verbindung – zusätzlich zu den Schemas main und temp. Das harte Limit liegt bei 125 und ist zur Compile-Zeit über SQLITE_MAX_ATTACHED einstellbar. Wer drüber kommt, kassiert einen too many attached databases-Fehler.

Kann ich in einem einzigen Statement über mehrere angehängte Datenbanken hinweg abfragen?

Ja. Sobald die Datenbank attached ist, schreibst du den Schemanamen vor jede Tabelle: SELECT * FROM main.users JOIN archive.orders ON .... JOINs, Subqueries und INSERT ... SELECT funktionieren schemaübergreifend. Auch Transaktionen umfassen alle angehängten Datenbanken – ein COMMIT ist also dateiübergreifend atomar.

Wie löse ich eine SQLite-Datenbank wieder ab?

Mit DETACH DATABASE alias. Die Datei auf der Festplatte bleibt unangetastet – DETACH schließt nur das Handle in der aktuellen Verbindung. main und temp lassen sich nicht detachen, und mitten in einer laufenden Transaktion geht es ebenfalls nicht.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S