删除所有表的命令

103

如何在SQLite中删除所有表?

同样地,我想删除所有索引。

11个回答

99

虽然没有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_
2
非常聪明。我们自己的增量升级系统只能执行比较版本的脚本,这个技巧不需要对其进行任何改进 :) - Ivan G.
3
注意:如果尝试第二次清理数据库(至少在最新版的sqlite中),可能会出现奇怪的“数据库文件格式不正确”的问题,但如果使用类似于“delete from sqlite_master where type in ('table', 'index', 'trigger')”这样的语句,则似乎可以完美地解决问题。 - mlvljr
这将有副作用,同时也会删除android_metadata表。下次打开数据库时,该表将被重新创建,但如果要立即重新创建它,可以将预写日志或外键约束翻转为与您配置的相反,然后再翻转回来。这将触发一个内部的reconfigure()调用,该调用将编写出android_metadata表。 - tophyr
@f470071 -- 将其添加到where类型子句中即可。 - Noah
显示剩余4条评论

93

我认为你不能一次性删除所有表格,但你可以通过以下方式获取命令:

select 'drop table ' || name || ';' from sqlite_master
    where type = 'table';
这将生成一个脚本,以便为您删除表。对于索引,只需将table替换为index即可。
您可以在 where 部分中使用其他子句来限制选择哪些表或索引(例如对于以“pax_”开头的表,“and name glob 'pax_*'”)。
您可以将此脚本的创建与运行合并到简单的bash(或cmd.exe)脚本中,这样只需要一个命令来运行。
如果您不关心数据库中的任何信息,我认为您可以直接从硬盘中删除存储文件 - 这可能更快。我从未测试过,但我认为它应该可以工作。

谢谢。非常奇怪,没有简单的命令,而是这个hacky SQL查询。 - alamodey
9
获取一个空的sqlite数据库最简单的方法就是删除文件,然后连接它。 - John Fouhy
3
因此,这是我的最后一段话,@JF。 - paxdiablo
触发器与表有什么关系? - rds
@rds,当您删除一个表时,所有与其相关的触发器也会被删除。保留这些触发器是没有意义的,因为它们不可能触发(因为表已经不存在了)。 - paxdiablo
忽略外键怎么样? - pleerock

37
rm db/development.sqlite3

是的,这确实会删除数据库,但 SQLite 中除了表之外还可能有其他东西。请查看我的完整答案以获取详细信息。 - Noah
11
如果数据库有多个连接处于打开状态,这样做将无法生效。在*nix系统上,这只会删除名称,并且连接将继续使用未命名的数据库文件,直到它们关闭句柄。如果目的是重写架构(删除所有表,创建新表),那么你会遇到麻烦。 - jbarlow
5
这个回答不应该被接受,因为它删除了数据库,其中包括所有存储过程、触发器等,而不仅仅是表。 - Hobbyist
2
我相信这个答案回答了提问者想要问的问题,那就是:"如何轻松地从头开始使用我的sqlite数据库?" 如果可能的话,有人应该编辑一下问题,使其更清晰明了。 - Akrikos
问题的字面意思是“删除所有表命令”。 - Nora Söderlund

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

6

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

第二行应该是这样的吗? cur.executescript(';'.join(["DROP TABLE IF EXISTS %s" %i[0] for i in tables])) 我的意思是,"i" 是一个 sqlite3 对象,但你需要表的名称。 - akoel
第二行应该是这样的吗? cur.executescript(';'.join(["DROP TABLE IF EXISTS %s" %i[0] for i in tables])) 我的意思是,"i" 是一个 sqlite3 对象,但你需要表的名称。 - undefined

4

除了删除表而不删除文件的其他答案所述,您还可以执行 delete from sqlite_sequence 来重置自增序列。


3

一旦您删除了所有表格(当表格消失时,索引也会消失),据我所知,在SQLite数据库中就没有剩余的内容了,尽管文件似乎不会缩小(根据我刚刚进行的快速测试)。因此,删除文件似乎是最快的方法 - 当您的应用程序尝试访问数据库文件时,它应该会被重新创建。


1
文件不会缩小,因为这不是SQLite的工作方式 - 只有在您清理文件(基本上是从头开始重新创建它)时,它才会将磁盘空间返回给操作系统。在此之前,该文件充满了可重用空间。 - paxdiablo
是的。如果您没有文件删除/创建权限,或者存在某些奇怪的多用户情况,那么删除所有表并进行清理可能是有意义的。否则,只需删除该项即可。 - Mike Woodhouse

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

如果要删除视图,请添加“view”关键字:

delete from sqlite_master where type in ('view', 'table', 'index', 'trigger');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接