sqlite Spalte löschen



  • Hallo,

    ich würde gerne in sqlite eine Spalte in einer Tabelle löschen. Nach einiger Recherche ist das ja nicht so ohne weiteres möglich, weil sqlite kein drop column kann (warum auch immer).

    Auf jeden Fall gibt es auf der sqlite FAQ einen Workaround mit dem das geht:

    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t1_backup(a,b);
    INSERT INTO t1_backup SELECT a,b FROM t1;
    DROP TABLE t1;
    CREATE TABLE t1(a,b);
    INSERT INTO t1 SELECT a,b FROM t1_backup;
    DROP TABLE t1_backup;
    COMMIT;
    

    Im Prinzip also alles einmal hin und her kopieren. Das klappt auch, aber es gibt ein Problem. Und zwar funktioniert nach einem solchen Löschvorgang das auto-increment der id eines Eintrages nicht mehr. Die Information dass es sich bei dem ersten Wert um ein auto-increment (bzw. den primary key) handelt, geht dabei anscheinend verloren.

    Da der Code direkt aus der offiziellen FAQ ist wundert mich dieses Fehlverhalten etwas.

    Deswegen meine Frage: Wie kann ich die obige Query abändern, so dass wirklich alle Informationen korrekt kopiert werden und die neue Tabelle wirklich in exakt dem gleichem Zustand (bis auf die zu löschende Spalte natürlich) ist wie vor dem Löschvorgang?



  • Funktioniert 'rowid' nicht oder soll 'a' ein primary-key sein?
    Falls letzters müsstest du das beim Erstellen der Temp-Table natürlich angeben.



  • Jockelx schrieb:

    Funktioniert 'rowid' nicht oder soll 'a' ein primary-key sein?
    Falls letzters müsstest du das beim Erstellen der Temp-Table natürlich angeben.

    Schon, aber woher kann ich das beim erstellen der Query "wissen"? Denn es muss ja nicht immer die erste Spalte der primary key sein, oder? Für das CREATE TABLE statement kann ich mir ja die nötige Syntax aus der Master Tablle holen:

    SELECT sql FROM sqlite_master;
    

    Nur für das INSERT INTO t1_backup SELECT a,b FROM t1; brauch ich ja die Namen der Werte (ohne die Attribute aus dem sql create String).

    Wie kommt man da am einfachsten ran?



  • happystudent schrieb:

    Da der Code direkt aus der offiziellen FAQ ist wundert mich dieses Fehlverhalten etwas.

    Das ist absolut kein Fehlverhalten. Du machst unter anderem:

    CREATE TABLE t1(a,b);
    

    Da erstellst Du die Tabelle, die Du vorher gelöscht hast neu. Und zwar mit den Spalten a und b ohne Typen. Da ist kein autoincrement oder primary key enthalten. Wenn Du die mit den weggesicherten Daten befüllst, passiert mit der Tabellenstruktur auch gar nichts.

    Ich kenne das FAQ nicht aber ich so etwas ist mit Sicherheit sinngemäß gemeint. Natürlich musst Du die Tabelle exakt so wieder anlegen, wie Du sie haben willst.



  • tntnet schrieb:

    Da erstellst Du die Tabelle, die Du vorher gelöscht hast neu. Und zwar mit den Spalten a und b ohne Typen. Da ist kein autoincrement oder primary key enthalten. Wenn Du die mit den weggesicherten Daten befüllst, passiert mit der Tabellenstruktur auch gar nichts.

    Ich kenne das FAQ nicht aber ich so etwas ist mit Sicherheit sinngemäß gemeint. Natürlich musst Du die Tabelle exakt so wieder anlegen, wie Du sie haben willst.

    Ja schon, das Erstellen der Tabelle bekomme ich inzwischen auch hin, mittels SELECT sql FROM sqlite_master, damit bekommt man ja genau den Code den man braucht um die Tabelle zu erstellen.

    Dann brauch ich ja noch die Spaltenwerte für das INSERT , die kann ich mir ja über PRAGMA table_info holen und das dann parsen.

    Problem ist, dass das Parsen gar nicht so einfach ist. Ich dachte erst an einen simplen String-Split am Leerzeichen, aber das geht ja nicht weil Spaltennamen theoretisch beliebig viele Leerzeichen enthalten können. Auch aus der Anzahl der Token wird es schwierig das herauszulesen, weil zum Beispiel der Datentyp, der ja in der dritten Spalte der table_info steht, auch aus mehreren Token zusammengesetzt sein kann (z.B. UNSIGNED INTEGER ). Auch muss ich ja dann überprüfen ob ein Spaltenname Leerzeichen enthält und wenn ja, diesen dann in Anführungszeichen setzen.

    Um das also wirklich 100% perfekt zu machen, bräuchte ich also fast einen vollständigen SQLite Parser und das kanns ja nicht sein?



  • Wieso weißt du denn nicht, welche Spalten deine Tabelle hat?



  • happystudent schrieb:

    Um das also wirklich 100% perfekt zu machen, bräuchte ich also fast einen vollständigen SQLite Parser

    Deine Definition von "fast" ist seltsam.

    happystudent schrieb:

    und das kanns ja nicht sein?

    Wieso nicht?
    Ansonsten: du kannst dir mal die C-API von SQLite angucken ob du Funktionen findest mittels derer man die Schema-Informationen "direkt" auslesen kann. Also ohne Umweg über SQL Statements und Result-Sets.



  • Spaltenkenner schrieb:

    Wieso weißt du denn nicht, welche Spalten deine Tabelle hat?

    Es soll halt für beliebige Tabellen funktionieren, deswegen will ich die nicht hardcoden.

    hustbaer schrieb:

    Deine Definition von "fast" ist seltsam.

    Ja ok, war "fast" ein bisschen übertrieben 😃

    hustbaer schrieb:

    Wieso nicht?
    Ansonsten: du kannst dir mal die C-API von SQLite angucken ob du Funktionen findest mittels derer man die Schema-Informationen "direkt" auslesen kann. Also ohne Umweg über SQL Statements und Result-Sets.

    Ja, habs jetzt mittels C-API hingekriegt. Danke auf jeden Fall 👍



  • happystudent schrieb:

    Wie kommt man da am einfachsten ran?

    PRAGMA table_info [tabName]

    in der 6. Spalte steht 0, wenn es kein PrimaryKey ist. Ansonsten ein Wert größer 0. Der Wert gibt dann die Position der Spalte im PK an, wenn es sich
    um einen zusammmen gesetzen PK handelt. Das ist aber nicht bei jeder sqlite-version so. In älteren Versionen hatten alle PK-Spalten den Wert 1.


Log in to reply