Lệnh thả tất cả các bảng


83

Lệnh bỏ tất cả các bảng trong SQLite là gì?

Tương tự, tôi muốn bỏ tất cả các chỉ mục.

Câu trả lời:


82

Tôi không nghĩ rằng bạn có thể bỏ tất cả các bảng trong một lần đánh nhưng bạn có thể làm như sau để nhận các lệnh:

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

Đầu ra của điều này là một tập lệnh sẽ thả các bảng cho bạn. Đối với các chỉ mục, chỉ cần thay thế bảng bằng chỉ mục.

Bạn có thể sử dụng các mệnh đề khác trong wherephần để giới hạn bảng hoặc chỉ mục nào được chọn (chẳng hạn như " and name glob 'pax_*'" cho những bảng bắt đầu bằng "pax_").

Bạn có thể kết hợp việc tạo tập lệnh này với việc chạy nó trong một tập lệnh bash (hoặc cmd.exe) đơn giản để chỉ có một lệnh để chạy.

Nếu bạn không quan tâm đến bất kỳ thông tin nào trong DB, tôi nghĩ bạn có thể xóa tệp được lưu trữ trong đĩa cứng - điều đó có thể nhanh hơn. Tôi chưa bao giờ thử nghiệm điều này nhưng tôi không thể hiểu tại sao nó không hoạt động.


Cảm ơn. Rất lạ là không có lệnh đơn giản nào mà thay vào đó là truy vấn SQL khó hiểu này.
alamodey

7
Chà, cách dễ nhất để có được một cơ sở dữ liệu sqlite trống chỉ là xóa tệp, và sau đó kết nối với nó ..
John Fouhy

2
Do đó, đoạn cuối cùng của tôi, @JF.
paxdiablo 09/02/09

Điều gì xảy ra với các trình kích hoạt được gắn vào bảng?
rds

@rds, khi bạn thả một bảng, tất cả các kích hoạt cho bảng đó cũng sẽ bị xóa. Sẽ không có ý nghĩa gì khi giữ các trigger xung quanh khi chúng không thể kích hoạt (vì bảng không còn tồn tại).
paxdiablo,

80

Mặc dù đúng là không có lệnh DROP ALL TABLES, nhưng bạn có thể sử dụng nhóm lệnh sau.

Lưu ý: Các lệnh này có khả năng làm hỏng cơ sở dữ liệu của bạn, vì vậy hãy đảm bảo bạn có bản sao lưu

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

sau đó bạn muốn khôi phục không gian đã xóa với

VACUUM;

và một bài kiểm tra tốt để đảm bảo mọi thứ đều ổn

PRAGMA INTEGRITY_CHECK;

1
làm thế nào để thực thi chúng trong onUpgrade () ??
AZ_

Đơn giản chỉ cần thực hiện DDL, điều đó đã đủ
Noah

Trong trường hợp vì một lý do điên rồ nào đó mà người khác có câu hỏi này, cách trên sẽ hoạt động để loại bỏ tất cả các bảng trong API cơ sở dữ liệu của Titanium Mobile.
Riley Dutton

2
Thông minh kinh khủng. Cây nhà lá vườn của chúng tôi gia tăng nâng cấp hệ thống chỉ có thể thực hiện các kịch bản so sánh các phiên bản, thủ thuật này không đòi hỏi bất kỳ cải tiến để nó :)
Ivan G.

3
LƯU Ý: điều này có thể gây ra các vấn đề kỳ lạ "tệp cơ sở dữ liệu không đúng định dạng" trong lần thử thứ hai để làm sạch cơ sở dữ liệu (ít nhất là với sqlite mới nhất), nhưng dường như hoạt động hoàn hảo nếu bạn sử dụng thứ gì đó tương tự delete from sqlite_master where type in ('table', 'index', 'trigger').
mlvljr

35
rm db/development.sqlite3

vâng, điều này sẽ xóa cơ sở dữ liệu, nhưng có thể có thứ khác trong sqlite ngoài bảng; Xem câu trả lời đầy đủ của tôi để biết chi tiết
Noah

9
Nếu cơ sở dữ liệu có nhiều kết nối đang mở, điều này sẽ không hoạt động. Trên * nix sẽ chỉ xóa tên và các kết nối sẽ tiếp tục hoạt động với tệp cơ sở dữ liệu chưa được đặt tên cho đến khi chúng đóng tay cầm. Nếu mục đích là viết lại lược đồ (bỏ tất cả các bảng, tạo bảng mới) thì bạn sẽ gặp rắc rối.
jbarlow

3
Đây không phải là câu trả lời được chấp nhận, vì nó đã xóa cơ sở dữ liệu, bao gồm tất cả các thủ tục được lưu trữ, trình kích hoạt, v.v., không chỉ các bảng.
sở thích

2
Tôi tin rằng câu trả lời này trả lời cho câu hỏi mà người đăng muốn hỏi là: "làm cách nào để tôi dễ dàng bắt đầu lại từ đầu với cơ sở dữ liệu sqlite của mình?" Ai đó có lẽ nên chỉnh sửa câu hỏi để rõ ràng hơn ... nếu có thể.
Akrikos

22

Tôi đã gặp vấn đề tương tự với SQLite và Android. Đây là Giải pháp của tôi:

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

Tôi muốn thêm vào các câu trả lời khác liên quan đến việc giảm bảng và không xóa tệp, mà bạn cũng có thể thực hiện delete from sqlite_sequenceđể đặt lại trình tự tăng tự động.


3

Khi bạn đã bỏ tất cả các bảng (và các chỉ mục sẽ biến mất khi hết bảng) thì không còn gì trong cơ sở dữ liệu SQLite theo như tôi biết, mặc dù tệp dường như không bị thu nhỏ (từ một thử nghiệm nhanh mà tôi vừa làm ).

Vì vậy, việc xóa tệp sẽ có vẻ là nhanh nhất - nó chỉ nên được tạo lại khi ứng dụng của bạn cố gắng truy cập tệp db.


1
Tệp không bị thu nhỏ vì đó không phải là cách sqlite hoạt động - nó sẽ chỉ trả lại dung lượng ổ đĩa cho HĐH nếu bạn hút tệp (về cơ bản là tạo lại từ đầu). Cho đến lúc đó, tệp đầy dung lượng có thể sử dụng lại.
paxdiablo 09/02/09

Yah! Vì vậy, bỏ tất cả các bảng và hút bụi sẽ có ý nghĩa nếu bạn không có đặc quyền xóa / tạo tệp hoặc có một số tình huống kỳ lạ có nhiều người dùng. Nếu không, chỉ cần xóa điều?
Mike Woodhouse

3

Sử dụng 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

Tôi đã gặp sự cố này trong Android và tôi đã viết một phương pháp tương tự như it-west.

Vì tôi đã sử dụng AUTOINCREMENTcác khóa chính trong các bảng của mình, nên có một bảng được gọi sqlite_sequence. SQLite sẽ gặp sự cố khi quy trình cố gắng loại bỏ bảng đó. Tôi cũng không thể bắt được ngoại lệ. Nhìn vào https://www.sqlite.org/fileformat.html#internal_schema_objects , tôi biết rằng có thể có một số bảng lược đồ nội bộ này mà tôi không muốn bỏ. Tài liệu nói rằng bất kỳ bảng nào trong số này có tên bắt đầu bằng sqlite_ vì vậy tôi đã viết phương pháp này

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

Tôi không thể nói đây là giải pháp chống đạn hay di động nhất, nhưng nó phù hợp với các tập lệnh thử nghiệm của tôi:

.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

Đoạn mã này chuyển hướng đầu ra đến một tệp tạm thời, xây dựng các lệnh 'bảng thả' mà tôi muốn chạy (gửi các lệnh tới tệp tạm thời), đặt đầu ra trở lại chuẩn, sau đó thực hiện các lệnh từ tệp, và cuối cùng loại bỏ tệp.


0

Hoặc tại dấu nhắc shell, chỉ trong hai dòng, không có tệp tạm thời được đặt tên, giả sử $ db là tên cơ sở dữ liệu SQLite:

echo "SELECT 'DROP TABLE ' || name ||';' FROM sqlite_master WHERE type = 'table';" |
    sqlite3 -readonly "$db" | sqlite3 "$db"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.