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


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.