Команда удаления всех таблиц

86

Какая команда удаляет все таблицы в SQLite?

Точно так же я хотел бы удалить все индексы.

Аламодей
источник

Ответы:

86

Я не думаю, что вы можете удалить все таблицы за один удар, но вы можете сделать следующее, чтобы получить команды:

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

Результатом этого будет сценарий, который сбросит таблицы за вас. Для индексов просто замените table на index.

Вы можете использовать другие предложения в whereразделе, чтобы ограничить выбор таблиц или индексов (например, « and name glob 'pax_*'» для тех, которые начинаются с «pax_»).

Вы можете объединить создание этого сценария с его запуском в простом сценарии bash (или cmd.exe), чтобы выполнить только одну команду.

Если вас не интересует какая-либо информация в базе данных, я думаю, вы можете просто удалить файл, в котором он хранится, с жесткого диска - это, вероятно, быстрее. Я никогда не тестировал это, но не понимаю, почему это не сработает.

Paxdiablo
источник
Благодарю. Очень странно, что нет простой команды, а вместо этого взломанный SQL-запрос.
alamodey
7
Ну, самый простой способ получить пустую базу данных sqlite - просто удалить файл, а затем подключиться к нему ..
Джон Фухи,
2
Отсюда мой последний абзац, @JF.
paxdiablo
Что происходит с триггерами, прикрепленными к таблице?
rds
@rds, когда вы удаляете таблицу, все триггеры для нее также удаляются. Нет смысла держать триггеры под рукой, если они не могут сработать (поскольку таблица больше не существует).
paxdiablo
83

Хотя это правда, что нет команды DROP ALL TABLES, вы можете использовать следующий набор команд.

Примечание. Эти команды могут повредить вашу базу данных, поэтому убедитесь, что у вас есть резервная копия.

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

затем вы хотите восстановить удаленное пространство с помощью

VACUUM;

и хороший тест, чтобы убедиться, что все в порядке

PRAGMA INTEGRITY_CHECK;
Ной
источник
1
как выполнить их в onUpgrade () ??
AZ_
Просто выполните DDL, этого достаточно
Ной
В случае, если по какой-то безумной причине у кого-то еще есть этот вопрос, вышеперечисленное помогает удалить все таблицы в API базы данных Titanium Mobile.
Райли Даттон,
2
Невероятно умно. Наша самодельная система инкрементного обновления может выполнять только скрипты, сравнивая версии, этот трюк не требует никаких улучшений :)
Иван Г.
3
ПРИМЕЧАНИЕ: это может вызвать странные проблемы «файл базы данных искажен» при второй попытке очистить базу данных (по крайней мере, с последним sqlite), но, похоже, работает безупречно, если вы используете что-то вроде delete from sqlite_master where type in ('table', 'index', 'trigger').
mlvljr
36
rm db/development.sqlite3
Аламодей
источник
да, это удаляет базу данных, но в sqlite может быть и другое, кроме таблиц; Подробности см. В моем полном ответе
Ной
9
Если в базе данных открыто несколько подключений, это не сработает. На * nix, который просто удалит имя, и соединения будут продолжать работать с безымянным файлом базы данных, пока они не закроют свои дескрипторы. Если намерение состоит в том, чтобы переписать схему (отбросить все таблицы, создать новые таблицы), тогда у вас будут проблемы.
jbarlow
3
Это не должен быть принятым ответом, поскольку он удалил базу данных, которая включает в себя все хранимые процедуры, триггеры и т. Д., А не только таблицы.
Hobbyist
2
Я считаю, что этот ответ действительно отвечает на вопрос, который хотел задать плакат: «Как мне легко начать с нуля с моей базой данных sqlite?» Кто-то, наверное, должен отредактировать вопрос, чтобы он был более ясным ... если это возможно.
Akrikos
22

У меня была такая же проблема с SQLite и Android. Вот мое решение:

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
источник
4

Я хотел бы добавить к другим ответам, связанным с удалением таблиц и не удалением файла, которые вы также можете выполнить delete from sqlite_sequenceдля сброса последовательностей автоинкремента.

Флавио Тордини
источник
4

Используя 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
источник
3

После того, как вы отбросили все таблицы (и индексы исчезнут, когда таблица переместится), то, насколько мне известно, в базе данных SQLite ничего не останется, хотя файл, похоже, не сжимается (из быстрого теста, который я только что сделал ).

Таким образом, удаление файла кажется самым быстрым - его нужно просто воссоздать, когда ваше приложение пытается получить доступ к файлу db.

Майк Вудхаус
источник
1
Файл не сжимается, потому что sqlite не работает - он вернет дисковое пространство ОС только в том случае, если вы очистите файл (в основном воссоздаете его с нуля). А пока в файле много места для повторного использования.
paxdiablo
Ага. Таким образом, удаление всех таблиц и очистка имеет смысл, если у вас нет прав на удаление / создание файлов или возникла какая-то странная многопользовательская ситуация. Иначе просто удалить вещь?
Майк Вудхаус,
2

У меня была эта проблема в Android, и я написал метод, похожий на it-west.

Поскольку я использовал AUTOINCREMENTпервичные ключи в своих таблицах, была таблица с именем sqlite_sequence. SQLite вылетал из строя, когда подпрограмма пыталась удалить эту таблицу. Я тоже не мог уловить исключения. Посмотрев на https://www.sqlite.org/fileformat.html#internal_schema_objects , я узнал, что могло быть несколько таких таблиц внутренней схемы, которые я не хотел бы отбрасывать. В документации указано, что имена любой из этих таблиц начинаются с sqlite_, поэтому я написал этот метод

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

Я не могу сказать, что это самое надежное или портативное решение, но оно работает для моих сценариев тестирования:

.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

Этот фрагмент кода перенаправляет вывод во временный файл, создает команды 'drop table', которые я хочу запустить (отправляя команды во временный файл), устанавливает стандартный вывод, затем выполняет команды из файла и, наконец, удаляет файл.

Мэтт Мэлоун
источник
0

Или в приглашении оболочки, всего в две строки, без именованного временного файла, если $ db - это имя базы данных SQLite:

echo "SELECT 'DROP TABLE ' || name ||';' FROM sqlite_master WHERE type = 'table';" |
    sqlite3 -readonly "$db" | sqlite3 "$db"
вершина горы
источник
0

Чтобы удалить также просмотры, добавьте ключевое слово 'view':

delete from sqlite_master where type in ('view', 'table', 'index', 'trigger');
Данило Шембри
источник