Usuń polecenie wszystkich tabel

86

Jakie jest polecenie usunięcia wszystkich tabel w SQLite?

Podobnie chciałbym usunąć wszystkie indeksy.

alamodey
źródło

Odpowiedzi:

86

Nie sądzę, abyś mógł upuścić wszystkie tabele jednym uderzeniem, ale możesz wykonać następujące czynności, aby uzyskać polecenia:

select 'drop table ' || name || ';' from sqlite_master
    where type = 'table';

Wynikiem tego jest skrypt, który usunie tabele za Ciebie. W przypadku indeksów wystarczy zastąpić tabelę indeksem.

Możesz użyć innych klauzul w wheresekcji, aby ograniczyć wybrane tabele lub indeksy (np. „ and name glob 'pax_*'” Dla tych zaczynających się od „pax_”).

Możesz połączyć utworzenie tego skryptu z uruchomieniem go w prostym skrypcie bash (lub cmd.exe), więc jest tylko jedno polecenie do uruchomienia.

Jeśli nie dbasz o żadne informacje w bazie danych, myślę, że możesz po prostu usunąć plik, w którym jest przechowywany, z dysku twardego - to prawdopodobnie szybciej. Nigdy tego nie testowałem, ale nie rozumiem, dlaczego to nie zadziała.

paxdiablo
źródło
Dzięki. Bardzo dziwne, że nie ma prostego polecenia, ale zamiast tego to hackerskie zapytanie SQL.
alamodey
7
Cóż, najłatwiejszym sposobem uzyskania pustej bazy danych sqlite jest po prostu usunięcie pliku, a następnie połączenie się z nim.
John Fouhy,
2
Stąd mój ostatni akapit, @JF.
paxdiablo
Co dzieje się z wyzwalaczami dołączonymi do stołu?
rds
@rds, kiedy upuszczasz tabelę, wszystkie wyzwalacze do niej są również usuwane. Nie ma sensu trzymać wyzwalaczy, gdy nie mogą one wystrzelić (ponieważ stół już nie istnieje).
paxdiablo
83

Chociaż prawdą jest, że nie ma polecenia DROP ALL TABLES, możesz użyć następującego zestawu poleceń.

Uwaga: te polecenia mogą potencjalnie uszkodzić bazę danych, więc upewnij się, że masz kopię zapasową

PRAGMA writable_schema = 1;
delete from sqlite_master where type in ('table', 'index', 'trigger');
PRAGMA writable_schema = 0;

następnie chcesz odzyskać usunięte miejsce za pomocą

VACUUM;

i dobry test, aby upewnić się, że wszystko jest w porządku

PRAGMA INTEGRITY_CHECK;
Noe
źródło
1
jak je wykonać w onUpgrade () ??
AZ_
Po prostu wykonaj DDL, to wystarczy
Noah
Jeśli z jakiegoś szalonego powodu ktoś inny ma to pytanie, powyższe działa, aby usunąć wszystkie tabele w interfejsie API bazy danych Titanium Mobile.
Riley Dutton
2
Niesamowicie sprytny. Nasz własny system przyrostowej aktualizacji może wykonywać tylko skrypty porównujące wersje, ta sztuczka nie wymaga żadnych ulepszeń :)
Ivan G.
3
UWAGA: przy drugiej próbie wyczyszczenia bazy danych (przynajmniej z najnowszą wersją sqlite) może to spowodować dziwne problemy „plik bazy danych jest źle sformułowany” , ale wydaje się działać bezbłędnie, jeśli używasz czegoś takiego jak delete from sqlite_master where type in ('table', 'index', 'trigger').
mlvljr
36
rm db/development.sqlite3
alamodey
źródło
tak, to usuwa bazę danych, ale w sqlite może być coś innego oprócz tabel; Zobacz moją pełną odpowiedź po szczegóły
Noah
9
Jeśli baza danych ma otwartych wiele połączeń, to nie zadziała. Na * nix, który po prostu usunie nazwę, a połączenia będą kontynuowane z nienazwanym plikiem bazy danych, dopóki nie zamkną swoich uchwytów. Jeśli zamierzasz przepisać schemat (usunąć wszystkie tabele, utworzyć nowe), będziesz miał kłopoty.
jbarlow
3
Nie powinna to być akceptowana odpowiedź, ponieważ spowodowała usunięcie bazy danych, która zawiera wszystkie procedury składowane, wyzwalacze itp., A nie tylko tabele.
Hobbyist
2
Wydaje mi się, że ta odpowiedź odpowiada na pytanie, które chciał zadać plakat, a które brzmi: „Jak łatwo rozpocząć od nowa z moją bazą danych sqlite?” Ktoś powinien prawdopodobnie zmienić pytanie, aby było bardziej jasne ... jeśli to możliwe.
Akrikos,
22

Miałem ten sam problem z SQLite i Androidem. Oto moje rozwiązanie:

List<String> tables = new ArrayList<String>();
Cursor cursor = db.rawQuery("SELECT * FROM sqlite_master WHERE type='table';", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
    String tableName = cursor.getString(1);
    if (!tableName.equals("android_metadata") &&
            !tableName.equals("sqlite_sequence"))
        tables.add(tableName);
    cursor.moveToNext();
}
cursor.close();

for(String tableName:tables) {
    db.execSQL("DROP TABLE IF EXISTS " + tableName);
}
it-west.net
źródło
4

Chciałbym dodać do innych odpowiedzi dotyczących usuwania tabel i nie usuwania pliku, które można również wykonać, delete from sqlite_sequenceaby zresetować sekwencje autoinkrementacji.

Flavio Tordini
źródło
4

Korzystanie z pysqlite:

tables = list(cur.execute("select name from sqlite_master where type is 'table'"))

cur.executescript(';'.join(["drop table if exists %s" %i for i in tables]))
user3467349
źródło
3

Po upuszczeniu wszystkich tabel (a indeksy znikną, gdy tabela zostanie przeniesiona), o ile wiem, w bazie danych SQLite nie ma nic, chociaż plik nie wydaje się zmniejszać (z szybkiego testu, który właśnie zrobiłem ).

Dlatego usunięcie pliku wydaje się być najszybsze - należy go odtworzyć, gdy aplikacja próbuje uzyskać dostęp do pliku db.

Mike Woodhouse
źródło
1
Plik nie kurczy się, ponieważ nie w ten sposób działa sqlite - zwróci miejsce na dysku do systemu operacyjnego, jeśli odkurzysz plik (w zasadzie odtworzysz go od zera). Do tego czasu plik jest pełen miejsca do ponownego wykorzystania.
paxdiablo
Tak. Porzucenie wszystkich tabel i odkurzenie miałoby sens, gdybyś nie miał uprawnień do usuwania / tworzenia plików lub była jakaś dziwna sytuacja z udziałem wielu użytkowników. W przeciwnym razie po prostu usuń rzecz?
Mike Woodhouse
2

Miałem ten problem w Androidzie i napisałem metodę podobną do it-west.

Ponieważ użyłem AUTOINCREMENTkluczy podstawowych w moich tabelach, powstała tabela o nazwie sqlite_sequence. SQLite ulegał awarii, gdy procedura próbowała usunąć tę tabelę. Nie mogłem też złapać wyjątku. Patrząc na https://www.sqlite.org/fileformat.html#internal_schema_objects , dowiedziałem się, że może istnieć kilka takich wewnętrznych tabel schematów , których nie chciałbym usuwać. Dokumentacja mówi, że każda z tych tabel ma nazwy zaczynające się od sqlite_, więc napisałem tę metodę

private void dropAllUserTables(SQLiteDatabase db) {
    Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
    //noinspection TryFinallyCanBeTryWithResources not available with API < 19
    try {
        List<String> tables = new ArrayList<>(cursor.getCount());

        while (cursor.moveToNext()) {
            tables.add(cursor.getString(0));
        }

        for (String table : tables) {
            if (table.startsWith("sqlite_")) {
                continue;
            }
            db.execSQL("DROP TABLE IF EXISTS " + table);
            Log.v(LOG_TAG, "Dropped table " + table);
        }
    } finally {
        cursor.close();
    }
}
Jon
źródło
1

Nie mogę powiedzieć, że jest to najbardziej kuloodporne lub przenośne rozwiązanie, ale działa w przypadku moich skryptów testowych:

.output /tmp/temp_drop_tables.sql
select 'drop table ' || name || ';' from sqlite_master where type = 'table';
.output stdout
.read /tmp/temp_drop_tables.sql
.system rm /tmp/temp_drop_tables.sql

Ten fragment kodu przekierowuje dane wyjściowe do pliku tymczasowego, konstruuje polecenia „drop table”, które chcę uruchomić (wysyłanie poleceń do pliku tymczasowego), ustawia wyjście z powrotem na standardowe wyjście, następnie wykonuje polecenia z pliku i na koniec usuwa plik.

Matt Malone
źródło
0

Lub w wierszu polecenia powłoki, w zaledwie dwóch wierszach, bez nazwanego pliku tymczasowego, zakładając, że $ db to nazwa bazy danych SQLite:

echo "SELECT 'DROP TABLE ' || name ||';' FROM sqlite_master WHERE type = 'table';" |
    sqlite3 -readonly "$db" | sqlite3 "$db"
szczyt
źródło
0

Aby usunąć również widoki, dodaj słowo kluczowe „widok”:

delete from sqlite_master where type in ('view', 'table', 'index', 'trigger');
Danilo Schembri
źródło