Відкиньте команду всіх таблиць


84

Яка команда видалити всі таблиці в SQLite?

Подібним чином я хотів би скинути всі індекси.

Відповіді:


83

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

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

Результат - це скрипт, який видалить таблиці для вас. Для індексів просто замініть таблицю на index.

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

Ви можете поєднати створення цього сценарію з його запуском у простому скрипті bash (або cmd.exe), щоб запустити лише одну команду.

Якщо вас не хвилює жодна інформація в БД, я думаю, ви можете просто видалити файл, у якому він зберігається, з жорсткого диска - це, швидше за все, швидше. Я ніколи цього не тестував, але не можу зрозуміти, чому це не спрацює.


Дякую. Дуже дивно, що немає простої команди, а замість цього вдалий запит SQL.
— alamodey

7
Ну, найпростіший спосіб отримати порожню базу даних sqlite - це просто видалити файл, а потім підключитися до нього ..
— Джон Фуші,

2
Звідси мій останній абзац, @JF.
— paxdiablo

Що відбувається з тригерами, прикріпленими до столу?
— rds

@rds, коли ви опускаєте таблицю, усі тригери для неї також видаляються. Немає сенсу тримати тригери, коли вони не можуть спрацювати (оскільки таблиця вже не існує).
— paxdiablo

80

Хоча це правда, що немає команди 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
Це не повинна бути прийнятою відповіддю, оскільки вона видалила базу даних, яка включає всі збережені процедури, тригери тощо, а не лише таблиці.
— Любітель

2
Я вважаю, що ця відповідь відповідає на запитання, яке планував задати плакат, а саме: "як мені легко почати все з нуля зі своєю базою даних sqlite?" Хтось, мабуть, повинен відредагувати питання, щоб бути більш зрозумілим ... якщо це можливо.
— Акрикос,

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

4

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


3

Як тільки ви скинете всі таблиці (і індекси зникнуть, коли таблиця перейде), тоді, наскільки мені відомо, у базі даних SQLite нічого не залишилось, хоча файл, здається, не зменшується (із швидкого тесту, який я щойно зробив) ).

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


1
Файл не стискається, оскільки sqlite працює не так - він поверне дисковий простір ОС лише у тому випадку, якщо ви пилососите файл (в основному відтворюєте його з нуля). До цього часу у файлі багато місця для багаторазового використання.
— paxdiablo

Я Тож скидання всіх таблиць і пилососування мало б сенс, якби у вас не було привілеїв на видалення / створення файлів, або була якась дивна багатокористувацька ситуація. Інакше просто видалити річ?
— Mike Woodhouse

3

Використання 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]))

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

Цей біт коду перенаправляє вихідні дані у тимчасовий файл, створює команди "падіння таблиці", які я хочу запустити (надсилання команд у тимчасовий файл), повертає вихід на стандартний вихід, потім виконує команди з файлу і, нарешті, видаляє файл.


0

Або в підказці оболонки, всього в два рядки, без іменованого тимчасового файлу, припускаючи, що $ db - це ім'я бази даних SQLite:

echo "SELECT 'DROP TABLE ' || name ||';' FROM sqlite_master WHERE type = 'table';" |
    sqlite3 -readonly "$db" | sqlite3 "$db"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.