Vor kurzem mussten wir einigen unserer vorhandenen SQLite-Datenbanktabellen Spalten hinzufügen. Dies kann mit gemacht werden ALTER TABLE ADD COLUMN
. Wenn die Tabelle bereits geändert wurde, möchten wir sie natürlich in Ruhe lassen. Leider unterstützt SQLite keine IF NOT EXISTS
Klausel für ALTER TABLE
.
Unsere aktuelle Problemumgehung besteht darin, die Anweisung ALTER TABLE auszuführen und alle Fehler "doppelter Spaltenname" zu ignorieren, genau wie in diesem Python-Beispiel (jedoch in C ++).
Unser üblicher Ansatz zum Einrichten von Datenbankschemata besteht jedoch darin, ein .sql-Skript mit CREATE TABLE IF NOT EXISTS
und CREATE INDEX IF NOT EXISTS
Anweisungen zu haben, die mit sqlite3_exec
oder über das sqlite3
Befehlszeilentool ausgeführt werden können . Wir können ALTER TABLE
diese Skriptdateien nicht einfügen, da diese Anweisung nicht ausgeführt wird, wenn sie fehlschlägt.
Ich möchte die Tabellendefinitionen an einem Ort haben und nicht zwischen SQL- und CPP-Dateien aufteilen. Gibt es eine Möglichkeit, eine Problemumgehung ALTER TABLE ADD COLUMN IF NOT EXISTS
in reinem SQLite SQL zu schreiben ?
quelle
user_version
? Ich gehe von Null aus, aber es wäre schön, wenn das dokumentiert wäre.IF
und dasALTER TABLE
keine Bedingung hat? Was meinst du mit "99% reines SQL"?user_version
scheint 0 zu sein, aber es ist wirklich ein benutzerdefinierter Wert, sodass Sie Ihren eigenen Anfangswert erstellen können.user_version
Anfangswert ist relevant, wenn Sie über eine vorhandene Datenbank verfügen und diese noch nie verwendetuser_version
haben, diese jedoch verwenden möchten. Daher müssen Sie davon ausgehen, dass sqlite sie auf einen bestimmten Anfangswert festgelegt hat.Eine Problemumgehung besteht darin, nur die Spalten zu erstellen und die Ausnahme / den Fehler abzufangen, die auftreten, wenn die Spalte bereits vorhanden ist. Wenn Sie mehrere Spalten hinzufügen, fügen Sie diese in separaten ALTER TABLE-Anweisungen hinzu, damit ein Duplikat nicht verhindert, dass die anderen erstellt werden.
Mit sqlite-net haben wir so etwas gemacht. Es ist nicht perfekt, da wir doppelte SQLite-Fehler nicht von anderen SQLite-Fehlern unterscheiden können.
quelle
SQLite unterstützt auch eine Pragma-Anweisung namens "table_info", die eine Zeile pro Spalte in einer Tabelle mit dem Namen der Spalte (und anderen Informationen zur Spalte) zurückgibt. Sie können dies in einer Abfrage verwenden, um nach der fehlenden Spalte zu suchen und, falls nicht vorhanden, die Tabelle zu ändern.
http://www.sqlite.org/pragma.html#pragma_table_info
quelle
Wenn Sie dies in einer DB-Upgrade-Anweisung tun, ist es möglicherweise am einfachsten, die ausgelöste Ausnahme abzufangen, wenn Sie versuchen, ein Feld hinzuzufügen, das möglicherweise bereits vorhanden ist.
quelle
Es gibt eine Methode von PRAGMA, die table_info (table_name) lautet und alle Informationen der Tabelle zurückgibt.
Hier ist eine Implementierung, wie es für die Prüfspalte verwendet werden kann oder nicht.
Sie können diese Abfrage auch ohne Schleife verwenden.
quelle
we give no shit about performance
:)).SELECT * FROM pragma_table_info(...)
(Beachten Sie SELECT und den Unterstrich zwischen Pragma und Tabelleninformationen). Nicht sicher, in welcher Version sie es tatsächlich hinzugefügt haben, es funktionierte nicht unter 3.16.0, aber es funktioniert unter 3.22.0.Für diejenigen, die
pragma table_info()
das Ergebnis als Teil eines größeren SQL verwenden möchten .Der Schlüsselteil ist,
pragma_table_info('<table_name>')
anstelle von zu verwendenpragma table_info('<table_name>')
.Diese Antwort ist von der Antwort von @Robert Hawkey inspiriert. Der Grund, warum ich es als neue Antwort poste, ist, dass ich nicht genug Ruf habe, um es als Kommentar zu posten.
quelle
Für den Fall, dass Sie dieses Problem in Flex / Adobe Air haben und sich zuerst hier befinden, habe ich eine Lösung gefunden und diese auf eine verwandte Frage gestellt: ADD COLUMN to sqlite db WENN NICHT EXISTIERT - flex / air sqlite?
Mein Kommentar hier: https://stackoverflow.com/a/24928437/2678219
quelle
Ich habe die obige Antwort in C # /. Net genommen und sie für Qt / C ++ umgeschrieben, nicht zu viel geändert, aber ich wollte sie hier für alle hinterlassen, die in Zukunft nach einer C ++ - Antwort suchen.
quelle
Alternativ können Sie die TSQL-Anweisung CASE-WHEN in Kombination mit pragma_table_info verwenden, um festzustellen, ob eine Spalte vorhanden ist:
quelle
Hier ist meine Lösung, aber in Python (ich habe versucht und konnte keinen Beitrag zum Thema Python finden):
Ich habe PRAGMA verwendet, um die Tabelleninformationen zu erhalten. Es gibt ein mehrdimensionales Array mit Informationen zu Spalten zurück - ein Array pro Spalte. Ich zähle die Anzahl der Arrays, um die Anzahl der Spalten zu erhalten. Wenn nicht genügend Spalten vorhanden sind, füge ich die Spalten mit dem Befehl ALTER TABLE hinzu.
quelle
Alle diese Antworten sind in Ordnung, wenn Sie jeweils eine Zeile ausführen. Die ursprüngliche Frage war jedoch, ein SQL-Skript einzugeben, das von einer einzelnen Datenbank ausgeführt werden würde, und für alle Lösungen (z. B. die Überprüfung, ob die Spalte im Voraus vorhanden ist) muss das ausführende Programm entweder wissen, welche Tabellen und welche Spalten werden geändert / hinzugefügt oder das Eingabeskript wird vorverarbeitet und analysiert, um diese Informationen zu ermitteln. Normalerweise werden Sie dies nicht in Echtzeit oder häufig ausführen. Die Idee, eine Ausnahme abzufangen, ist also akzeptabel und geht dann weiter. Darin liegt das Problem ... wie man weitergeht. Glücklicherweise gibt uns die Fehlermeldung alle Informationen, die wir dazu benötigen. Die Idee ist, die SQL auszuführen, wenn es Ausnahmen bei einem Aufruf der Änderungstabelle gibt. Wir können die Zeile der Änderungstabelle in der SQL finden und die verbleibenden Zeilen zurückgeben und ausführen, bis sie entweder erfolgreich ist oder keine übereinstimmenden Zeilen der Änderungstabelle mehr gefunden werden können. Hier ist ein Beispielcode, in dem wir SQL-Skripte in einem Array haben. Wir iterieren das Array, das jedes Skript ausführt. Wir rufen es zweimal auf, damit der Befehl alter table fehlschlägt, aber das Programm ist erfolgreich, da wir den Befehl alter table aus der SQL entfernen und den aktualisierten Code erneut ausführen.
erwartete Ausgabe
quelle