Usuń polecenie wszystkich tabel


86

Jakie jest polecenie usunięcia wszystkich tabel w SQLite?

Podobnie chciałbym usunąć wszystkie indeksy.

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.


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;

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

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);
}

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.


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]))

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.


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();
    }
}

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.


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"

0

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

delete from sqlite_master where type in ('view', 'table', 'index', 'trigger');
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.