SQLite obsługuje ograniczony podzbiór ALTER TABLE. Polecenie ALTER TABLE w SQLite pozwala użytkownikowi zmienić nazwę tabeli lub dodać nową kolumnę do istniejącej tabeli. Nie można zmienić nazwy kolumny, usunąć kolumny ani dodać lub usunąć ograniczeń z tabeli.
Możesz:
utwórz nowy stół jako ten, który próbujesz zmienić,
Przed wykonaniem tej sekwencji oraz w przypadkach, w których istnieją tabele zewnętrzne odnoszące się do tej tabeli, należy wywołać PRAGMA foreign_keys=OFF. W takim przypadku po wykonaniu tej sekwencji należy wywołać PRAGMA foreign_keys=ON, aby ponownie włączyć klucze obce.
PazO
Jak kopiujesz również klucz i indeksy Freoign?
Jonathan
tak długo, jak najpierw utworzysz nową tabelę zamiast opcji Utwórz z zaznaczenia, będzie ona zawierała wszystkie te elementy.
Napisałem implementację Java w oparciu o zalecany sposób Sqlite:
private void dropColumn(SQLiteDatabase db,
ConnectionSource connectionSource,
String createTableCmd,
String tableName,
String[] colsToRemove) throws java.sql.SQLException {
List<String> updatedTableColumns = getTableColumns(tableName);// Remove the columns we don't want anymore from the table's list of columns
updatedTableColumns.removeAll(Arrays.asList(colsToRemove));
String columnsSeperated = TextUtils.join(",", updatedTableColumns);
db.execSQL("ALTER TABLE "+ tableName +" RENAME TO "+ tableName +"_old;");// Creating the tableon its new format (no redundant columns)
db.execSQL(createTableCmd);// Populating the tablewith the data
db.execSQL("INSERT INTO "+ tableName +"("+ columnsSeperated +") SELECT "+ columnsSeperated +" FROM "+ tableName +"_old;");
db.execSQL("DROP TABLE "+ tableName +"_old;");}
Aby uzyskać kolumnę tabeli, użyłem „PRAGMA table_info”:
public List<String> getTableColumns(String tableName){
ArrayList<String> columns = new ArrayList<String>();
String cmd ="pragma table_info("+ tableName +");";Cursor cur = getDB().rawQuery(cmd,null);while(cur.moveToNext()){
columns.add(cur.getString(cur.getColumnIndex("name")));}
cur.close();return columns;}
Napisałem o tym na swoim blogu, możesz tam znaleźć więcej wyjaśnień:
Byłoby lepiej, gdyby dokonano tego w jednej transakcji, niż potencjalnie pozwalając innemu kodowi zobaczyć rzeczy w stanie przejściowym.
Donal Fellows
Ten kod zwykle uruchamiam podczas aktualizacji bazy danych, gdy inny kod nie działa jednocześnie. Możesz utworzyć transakcję i wykonać w niej wszystkie te polecenia.
Udinic,
3
Jestem prawie pewien, że jeśli użyjesz tego rozwiązania, kolumny w tabeli wyników będą zupełnie puste - nie pozostaną żadne informacje o typie, PK, FK, wartości domyślne, unikalne lub ograniczenia sprawdzania. Wszystko, co importuje do nowej tabeli, to nazwa kolumny. Ponadto, ponieważ nie wyłącza kluczy obcych przed uruchomieniem, dane w innych tabelach również mogą zostać zepsute.
ACK_stoverflow
4
Alternatywnie, zamiast robić INSERTinstrukcję, możesz również utworzyć nową tabelę, wykonując"CREAT TABLE" + tableName + "AS SELECT " + columnsSeperated + " FROM " + tableName + "_old;"
Robert
26
Jak zauważyli inni
Nie można zmienić nazwy kolumny, usunąć kolumny ani dodać lub usunąć ograniczeń z tabeli.
Chociaż zawsze możesz utworzyć nowy stół, a następnie upuścić starszy. Spróbuję wyjaśnić to obejście przykładem.
sqlite>.schemaCREATETABLE person(
id INTEGER PRIMARYKEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
sqlite>select*from person ;
id first_name last_name age height
---------- ---------- ---------- ---------- ----------0 john doe 201701 foo bar 25171
Teraz chcesz usunąć kolumnę heightz tej tabeli.
Utwórz kolejną tabelę o nazwie new_person
sqlite>CREATETABLE new_person(...> id INTEGER PRIMARYKEY,...> first_name TEXT,...> last_name TEXT,...> age INTEGER
...>);
sqlite>
Teraz skopiuj dane ze starej tabeli
sqlite>INSERTINTO new_person
...>SELECT id, first_name, last_name, age FROM person ;
sqlite>select*from new_person ;
id first_name last_name age
---------- ---------- ---------- ----------0 john doe 201 foo bar 25
sqlite>
Teraz upuść persontabelę i zmień nazwę new_personnaperson
sqlite>DROPTABLEIFEXISTS person ;
sqlite>ALTERTABLE new_person RENAME TO person ;
sqlite>
Więc teraz, jeśli to zrobisz .schema, zobaczysz
sqlite>.schemaCREATETABLE"person"(
id INTEGER PRIMARYKEY,
first_name TEXT,
last_name TEXT,
age INTEGER
);
Jak zauważyli inni, ALTER TABLEoświadczenie sqlite nie obsługuje DROP COLUMN, a standardowa recepta na to nie zachowuje ograniczeń i wskaźników.
Oto kod Pythona, aby to zrobić ogólnie, zachowując wszystkie kluczowe ograniczenia i indeksy.
Przed użyciem wykonaj kopię zapasową bazy danych! Ta funkcja polega na sprawdzeniu oryginalnej instrukcji CREATE TABLE i jest potencjalnie trochę niebezpieczna - na przykład zrobi coś złego, jeśli identyfikator zawiera osadzony przecinek lub nawias.
Jeśli ktoś chciałby przyczynić się do lepszego sposobu parsowania SQL, byłoby świetnie!
AKTUALIZACJA Znalazłem lepszy sposób na analizę za pomocąsqlparsepakietuopen source. Jeśli jest jakieś zainteresowanie, opublikuję go tutaj, po prostu zostaw komentarz z prośbą o to ...
import re
import random
def DROP_COLUMN(db,table,column):
columns =[ c[1]for c in db.execute("PRAGMA table_info(%s)"%table)]
columns =[ c for c in columns if c !=column]
sql = db.execute("SELECT sql from sqlite_master where name = '%s'"%table).fetchone()[0]
sql = format(sql)
lines = sql.splitlines()
findcol = r'\b%s\b'%column
keeplines =[ line for line in lines ifnot re.search(findcol, line)]create='\n'.join(keeplines)create= re.sub(r',(\s*\))', r'\1',create)
temp ='tmp%d'% random.randint(1e8,1e9)
db.execute("ALTER TABLE %(old)s RENAME TO %(new)s"%{'old':table,'new': temp })
db.execute(create)
db.execute("""
INSERT INTO %(new)s ( %(columns)s )
SELECT %(columns)s FROM %(old)s
"""%{'old': temp,'new':table,'columns':', '.join(columns)})
db.execute("DROP TABLE %s"% temp)
def format(sql):
sql = sql.replace(",",",\n")
sql = sql.replace("(","(\n")
sql = sql.replace(")","\n)")return sql
@ LasseV.Karlsen Zrobiłem kilka testów i powinno ono utrzymywać ograniczenia klucza obcego, ponieważ wydaje się, że są one wymuszane przez nazwę tabeli.
spam_eggs
Jak mogę uruchomić go z Javy?
Leos Literak,
4
I przepisał odpowiedź @Udinic tak, że kod generuje zapytanie tworzenia tabeli automatycznie . To też nie potrzebuje ConnectionSource. Musi to również zrobić w ramach transakcji .
public static String getOneTableDbSchema(SQLiteDatabase db, String tableName){Cursor c = db.rawQuery("SELECT * FROM `sqlite_master` WHERE `type` = 'table' AND `name` = '"+ tableName +"'",null);
String result =null;if(c.moveToFirst()){
result = c.getString(c.getColumnIndex("sql"));}
c.close();return result;}public List<String> getTableColumns(SQLiteDatabase db, String tableName){
ArrayList<String> columns = new ArrayList<>();
String cmd ="pragma table_info("+ tableName +");";Cursor cur = db.rawQuery(cmd,null);while(cur.moveToNext()){
columns.add(cur.getString(cur.getColumnIndex("name")));}
cur.close();return columns;}
private void dropColumn(SQLiteDatabase db, String tableName, String[] columnsToRemove){
db.beginTransaction();
try {
List<String> columnNamesWithoutRemovedOnes = getTableColumns(db, tableName);// Remove the columns we don't want anymore from the table's list of columns
columnNamesWithoutRemovedOnes.removeAll(Arrays.asList(columnsToRemove));
String newColumnNamesSeparated = TextUtils.join(" , ", columnNamesWithoutRemovedOnes);
String sql = getOneTableDbSchema(db, tableName);// Extract the SQL query that contains only columns
String oldColumnsSql = sql.substring(sql.indexOf("(")+1, sql.lastIndexOf(")"));
db.execSQL("ALTER TABLE "+ tableName +" RENAME TO "+ tableName +"_old;");
db.execSQL("CREATE TABLE `"+ tableName +"` ("+ getSqlWithoutRemovedColumns(oldColumnsSql, columnsToRemove)+");");
db.execSQL("INSERT INTO "+ tableName +"("+ newColumnNamesSeparated +") SELECT "+ newColumnNamesSeparated +" FROM "+ tableName +"_old;");
db.execSQL("DROP TABLE "+ tableName +"_old;");
db.setTransactionSuccessful();} catch {//Error inbetweendatabasetransaction} finally {
db.endTransaction();}}
W głównym widoku karty Database Structurekliknij nazwę tabeli. Włączony Modify Tablezostaje przycisk , który otwiera nowe okno, w którym możesz wybrać kolumnę / pole i je usunąć.
możesz użyć Sqlitebrowser. W trybie przeglądarki dla odpowiedniej bazy danych i tabeli, w strukturze zakładki -bazy danych, po opcji Modyfikuj tabelę, odpowiednią kolumnę można usunąć.
Myślę, że chcesz zrobić migrację bazy danych. Upuszczanie kolumny nie istnieje w SQLite. Możesz jednak dodać dodatkową kolumnę, używając zapytania ALTER w tabeli.
Możesz użyć SQlite Administrator do zmiany nazw kolumn. Kliknij prawym przyciskiem myszy nazwę tabeli i wybierz Edytuj tabelę. Tutaj znajdziesz strukturę tabeli i możesz łatwo zmienić jej nazwę.
CREATETABLE person(
id INTEGER PRIMARYKEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
możesz użyć CREATE TABLE...ASinstrukcji typu CREATE TABLE person2 AS SELECT id, first_name, last_name, age FROM person;, tj. pominąć kolumny, których nie chcesz. Następnie upuść oryginalny personstół i zmień nazwę nowego.
Zauważ, że ta metoda tworzy tabelę bez PODSTAWOWEGO KLUCZA i żadnych ograniczeń. Aby je zachować, wykorzystaj metody opisane w innych, aby utworzyć nową tabelę lub użyj tabeli tymczasowej jako pośredniej.
Ta odpowiedź na inne pytanie ma na celu modyfikację kolumny, ale uważam, że część odpowiedzi może również przynieść użyteczne podejście, jeśli masz wiele kolumn i nie chcesz ręcznie wpisywać większości z nich dla instrukcji INSERT:
Możesz zrzucić bazę danych zgodnie z opisem w powyższym linku, a następnie pobrać instrukcję „create table” i szablon „insert” z tego zrzutu, a następnie postępować zgodnie z instrukcjami zawartymi we wpisie FAQ SQLite „Jak dodać lub usunąć kolumny z istniejącego tabela w SQLite. ” (FAQ znajduje się w innym miejscu na tej stronie).
Właśnie uświadomiłem sobie, że zrzut domyślnie nie zawiera nazw kolumn we wstawce. Równie dobrze może być po prostu użycie pragmy .schema do przechwycenia nazw kolumn, ponieważ w obu przypadkach trzeba będzie usunąć deklaracje typu.
import sqlite3 as db
import random
import string
QUERY_TEMPLATE_GET_COLUMNS ="PRAGMA table_info(@table_name)"
QUERY_TEMPLATE_DROP_COLUMN ="""
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE @tmp_table(@columns_to_keep);
INSERT INTO @tmp_table SELECT @columns_to_keep FROM @table_name;
DROP TABLE @table_name;
CREATE TABLE @table_name(@columns_to_keep);
INSERT INTO @table_name SELECT @columns_to_keep FROM @tmp_table;
DROP TABLE @tmp_table;
COMMIT;
"""
def drop_column(db_file, table_name, column_name):
con = db.connect(db_file)
QUERY_GET_COLUMNS = QUERY_TEMPLATE_GET_COLUMNS.replace("@table_name", table_name)
query_res = con.execute(QUERY_GET_COLUMNS).fetchall()
columns_list_to_keep =[i[1]for i in query_res if i[1]!= column_name]
columns_to_keep =",".join(columns_list_to_keep)
tmp_table ="tmp_%s"%"".join(random.sample(string.ascii_lowercase,10))
QUERY_DROP_COLUMN = QUERY_TEMPLATE_DROP_COLUMN.replace("@table_name", table_name)\.replace("@tmp_table", tmp_table).replace("@columns_to_keep", columns_to_keep)
con.executescript(QUERY_DROP_COLUMN)
con.close()
drop_column(DB_FILE, TABLE_NAME, COLUMN_NAME)
Ten skrypt najpierw tworzy losową tabelę tymczasową i wstawia dane tylko niezbędnych kolumn z wyjątkiem tej, która zostanie usunięta. Następnie przywraca oryginalny stół na podstawie tabeli tymczasowej i upuszcza tabelę tymczasową.
Odpowiedzi:
ALTER TABLE SQLite
Możesz:
źródło
PRAGMA foreign_keys=OFF
. W takim przypadku po wykonaniu tej sekwencji należy wywołaćPRAGMA foreign_keys=ON
, aby ponownie włączyć klucze obce.RENAME COLUMN
jest obsługiwany. 🎉 sqlite.org/releaselog/3_25_0.htmlNapisałem implementację Java w oparciu o zalecany sposób Sqlite:
Aby uzyskać kolumnę tabeli, użyłem „PRAGMA table_info”:
Napisałem o tym na swoim blogu, możesz tam znaleźć więcej wyjaśnień:
http://udinic.wordpress.com/2012/05/09/sqlite-drop-column-support/
źródło
INSERT
instrukcję, możesz również utworzyć nową tabelę, wykonując"CREAT TABLE" + tableName + "AS SELECT " + columnsSeperated + " FROM " + tableName + "_old;"
Jak zauważyli inni
źródło: http://www.sqlite.org/lang_altertable.html
Chociaż zawsze możesz utworzyć nowy stół, a następnie upuścić starszy. Spróbuję wyjaśnić to obejście przykładem.
Teraz chcesz usunąć kolumnę
height
z tej tabeli.Utwórz kolejną tabelę o nazwie
new_person
Teraz skopiuj dane ze starej tabeli
Teraz upuść
person
tabelę i zmień nazwęnew_person
naperson
Więc teraz, jeśli to zrobisz
.schema
, zobaczyszźródło
CREATE TABLE new_person AS SELECT id, first_name, last_name, age FROM person;
http://www.sqlite.org/lang_altertable.html
Jak widać na schemacie, obsługiwana jest tylko opcja DODAJ KOLUMNĘ. Istnieje jednak (dość ciężkie) obejście: http://www.sqlite.org/faq.html#q11
źródło
Nie możemy upuścić określonej kolumny w SQLite 3. Zobacz FAQ .
źródło
Jak zauważyli inni,
ALTER TABLE
oświadczenie sqlite nie obsługujeDROP COLUMN
, a standardowa recepta na to nie zachowuje ograniczeń i wskaźników.Oto kod Pythona, aby to zrobić ogólnie, zachowując wszystkie kluczowe ograniczenia i indeksy.
Przed użyciem wykonaj kopię zapasową bazy danych! Ta funkcja polega na sprawdzeniu oryginalnej instrukcji CREATE TABLE i jest potencjalnie trochę niebezpieczna - na przykład zrobi coś złego, jeśli identyfikator zawiera osadzony przecinek lub nawias.
Jeśli ktoś chciałby przyczynić się do lepszego sposobu parsowania SQL, byłoby świetnie!
AKTUALIZACJA Znalazłem lepszy sposób na analizę za pomocą
sqlparse
pakietuopen source. Jeśli jest jakieś zainteresowanie, opublikuję go tutaj, po prostu zostaw komentarz z prośbą o to ...źródło
I przepisał odpowiedź @Udinic tak, że kod generuje zapytanie tworzenia tabeli automatycznie . To też nie potrzebuje
ConnectionSource
. Musi to również zrobić w ramach transakcji .źródło
Przeglądarka DB dla SQLite pozwala dodawać lub upuszczać kolumny.
W głównym widoku karty Database Structurekliknij nazwę tabeli. Włączony Modify Tablezostaje przycisk , który otwiera nowe okno, w którym możesz wybrać kolumnę / pole i je usunąć.
źródło
możesz użyć Sqlitebrowser. W trybie przeglądarki dla odpowiedniej bazy danych i tabeli, w strukturze zakładki -bazy danych, po opcji Modyfikuj tabelę, odpowiednią kolumnę można usunąć.
źródło
Poprawiłem odpowiedź user2638929 i teraz zachowuje typ kolumny, klucz podstawowy, wartość domyślną itp.
PS. Użyłem tutaj
android.arch.persistence.db.SupportSQLiteDatabase
, ale możesz łatwo zmodyfikować go do użyciaandroid.database.sqlite.SQLiteDatabase
źródło
Myślę, że chcesz zrobić migrację bazy danych. Upuszczanie kolumny nie istnieje w SQLite. Możesz jednak dodać dodatkową kolumnę, używając zapytania ALTER w tabeli.
źródło
Możesz użyć SQlite Administrator do zmiany nazw kolumn. Kliknij prawym przyciskiem myszy nazwę tabeli i wybierz Edytuj tabelę. Tutaj znajdziesz strukturę tabeli i możesz łatwo zmienić jej nazwę.
źródło
Ponieważ SQLite ma ograniczoną obsługę ALTER TABLE, możesz więc DODAJ kolumnę tylko na końcu tabeli LUB ZMIEŃ TABELĘ w SQLite.
Oto najlepsza odpowiedź na pytanie JAK USUNĄĆ KOLUMNĘ Z SQLITE?
odwiedź Usuń kolumnę z tabeli SQLite
źródło
Jako alternatywa:
Jeśli masz tabelę ze schematem
możesz użyć
CREATE TABLE...AS
instrukcji typuCREATE TABLE person2 AS SELECT id, first_name, last_name, age FROM person;
, tj. pominąć kolumny, których nie chcesz. Następnie upuść oryginalnyperson
stół i zmień nazwę nowego.Zauważ, że ta metoda tworzy tabelę bez PODSTAWOWEGO KLUCZA i żadnych ograniczeń. Aby je zachować, wykorzystaj metody opisane w innych, aby utworzyć nową tabelę lub użyj tabeli tymczasowej jako pośredniej.
źródło
Ta odpowiedź na inne pytanie ma na celu modyfikację kolumny, ale uważam, że część odpowiedzi może również przynieść użyteczne podejście, jeśli masz wiele kolumn i nie chcesz ręcznie wpisywać większości z nich dla instrukcji INSERT:
https://stackoverflow.com/a/10385666
Możesz zrzucić bazę danych zgodnie z opisem w powyższym linku, a następnie pobrać instrukcję „create table” i szablon „insert” z tego zrzutu, a następnie postępować zgodnie z instrukcjami zawartymi we wpisie FAQ SQLite „Jak dodać lub usunąć kolumny z istniejącego tabela w SQLite. ” (FAQ znajduje się w innym miejscu na tej stronie).
źródło
Wdrożenie
Python
oparte na informacjach pod adresem http://www.sqlite.org/faq.html#q11 .Ten skrypt najpierw tworzy losową tabelę tymczasową i wstawia dane tylko niezbędnych kolumn z wyjątkiem tej, która zostanie usunięta. Następnie przywraca oryginalny stół na podstawie tabeli tymczasowej i upuszcza tabelę tymczasową.
źródło
Moje rozwiązanie, wystarczy wywołać tę metodę.
I pomocnicza metoda, aby uzyskać kolumny:
źródło
i po prostu wywołaj metodę
źródło
Teraz możesz także używać przeglądarki DB dla SQLite do manipulowania kolumnami
źródło
przykład, aby dodać kolumnę: -
tutaj uczeń to nazwa_tabeli, a TOB to nazwa_kolumny, którą należy dodać.
Działa i jest testowany.
źródło