Làm cách nào để kiểm tra SQLite xem bảng có tồn tại không?


894

Làm thế nào để tôi, đáng tin cậy , kiểm tra SQLite, liệu một bảng người dùng cụ thể có tồn tại không?

Tôi không yêu cầu những cách không đáng tin cậy như kiểm tra xem "select *" trên bảng có trả về lỗi hay không (đây có phải là một ý tưởng hay không?).

Lý do là như thế này:

Trong chương trình của tôi, tôi cần tạo và sau đó điền vào một số bảng nếu chúng chưa tồn tại.

Nếu chúng đã tồn tại, tôi cần cập nhật một số bảng.

Tôi có nên thực hiện một số đường dẫn khác thay vào đó để báo hiệu rằng các bảng trong câu hỏi đã được tạo - ví dụ, bằng cách tạo / đặt / đặt một cờ nhất định trong tệp cài đặt / khởi tạo chương trình của tôi trên đĩa hoặc một cái gì đó?

Hay cách tiếp cận của tôi có ý nghĩa?


SQLite sẽ đưa ra một ngoại lệ nếu bảng trong vùng chọn không tồn tại. Đơn giản là không cần bất kỳ công việc ưa thích hơn.
NoChance

34
@NoChance nó sẽ, nhưng số lượng những thứ khác cũng vậy. Điều đó giống như nhìn thấy nếu cái cây đó thực sự ở đó bằng cách lái xe về phía trước với đôi mắt nhắm nghiền, bạn sẽ tìm ra cách này hay cách khác :)
randomsock

@randomsock, ví dụ hay, nhưng hơi đáng sợ, đặc biệt nếu chiếc xe là xe của tôi ...
NoChance

@randomsock, tôi không biết hội nghị sqlite là gì, nhưng việc xin tha thứ nhiều hơn là cho phép. tức là bắt ngoại lệ thay vì sử dụng một điều kiện.
Eric

1
@Eric Hiện tại, câu hỏi không liên quan đến Python, nhưng giả sử nó đã xảy ra, lỗi là do chung chung sqlite3.OperationalError, do đó bạn phải phân tích thông báo lỗi để đảm bảo rằng thông báo "bảng TABLE_NAME đã tồn tại" khi bạn tạo một bảng và nếu không, sẽ khắc phục lỗi và tôi nghĩ rằng không có gì đảm bảo rằng lỗi sẽ không thay đổi.
Markus von Broady

Câu trả lời:


1022

Tôi đã bỏ lỡ câu hỏi thường gặp đó.

Dù sao, để tham khảo trong tương lai, truy vấn đầy đủ là:

SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';

Trong trường hợp {table_name}là tên của bảng để kiểm tra.

Phần tài liệu để tham khảo: Định dạng tệp cơ sở dữ liệu. 2.6. Lưu trữ lược đồ cơ sở dữ liệu SQL

  • Điều này sẽ trả về một danh sách các bảng với tên được chỉ định; nghĩa là, con trỏ sẽ có số 0 (không tồn tại) hoặc số 1 (không tồn tại)

7
Tài liệu SQLite nào bao gồm các bảng hệ thống này?
Pawel Veselov

29
@Pawel Veselov: Phần có tiêu đề "Định dạng tệp cho cơ sở dữ liệu SQLite": sqlite.org/fileformat2.html
Bryan Oakley

14
Điều này sẽ không làm việc cho các bảng TEMP, tuy nhiên. Các bảng TEMP nằm trong "sqlite_temp_master."
PatchyFog

11
Điều này có trả lại một boolean? Nó trả về cái gì nếu bảng không tồn tại?
Dagroom

8
@Dagrooms Điều này sẽ trả về một danh sách các bảng với tên được chỉ định; nghĩa là, con trỏ sẽ có số 0 (không tồn tại) hoặc số 1 (không tồn tại).
Tăng cường

555

Nếu bạn đang sử dụng SQLite phiên bản 3.3+, bạn có thể dễ dàng tạo bảng với:

create table if not exists TableName (col1 typ1, ..., colN typN)

Theo cùng một cách, bạn chỉ có thể xóa một bảng nếu nó tồn tại bằng cách sử dụng:

drop table if exists TableName

3
Lưu ý rằng create tablecâu lệnh không đầy đủ (thiếu đặc tả cột bảng).
Eric Platon

11
cũng có cấu trúc tương tự cho các chỉ mục: tạo chỉ mục nếu không tồn tại TableName_col1 trên TableName (col1)
lowTech

26
Đây không phải là câu trả lời được chấp nhận, nhưng sẽ là nếu câu hỏi được diễn đạt khác nhau. OP đã không hỏi cách kiểm tra bảng trước khi thả hoặc tạo. Điều gì nếu bạn phải truy vấn một bảng có thể không tồn tại? Đây là vấn đề tôi đang phải đối mặt và câu trả lời được chấp nhận hoạt động tốt nhất trong tuyên bố vấn đề chung này. Đây là một thay thế nhanh chóng tốt.
Dagroom

@Dagroom, bạn có thể đúng. Mặc dù OP không hỏi điều này, tôi đã tìm câu trả lời này :)
Earik87

169

Một biến thể sẽ là sử dụng CHỌN COUNT (*) thay vì CHỌN TÊN, tức là

SELECT count(*) FROM sqlite_master WHERE type='table' AND name='table_name';

Điều này sẽ trả về 0, nếu bảng không tồn tại, 1 nếu có. Điều này có thể hữu ích trong lập trình của bạn vì một kết quả số nhanh hơn / dễ xử lý hơn. Phần sau đây minh họa cách bạn sẽ làm điều này trong Android bằng SQLiteDatabase, Coder, rawQuery với các tham số.

boolean tableExists(SQLiteDatabase db, String tableName)
{
    if (tableName == null || db == null || !db.isOpen())
    {
        return false;
    }
    Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type = ? AND name = ?", new String[] {"table", tableName});
    if (!cursor.moveToFirst())
    {
        cursor.close();
        return false;
    }
    int count = cursor.getInt(0);
    cursor.close();
    return count > 0;
}

33
Tôi tin rằng "CHỌN 1" sẽ còn nhanh hơn nữa.
PatchyFog

Tại sao con trỏ.getInt (0) bằng với số lượng bản ghi trong cơ sở dữ liệu?
Semyon Danilov

1
Chúng tôi đang đếm số lần BẢNG xuất hiện trong lược đồ sqlite. Tổng số 0 có nghĩa là bảng không tồn tại. Tổng số 1 có nghĩa là bảng tồn tại. Đây là hai giá trị dự kiến ​​duy nhất của đếm.
Stephen Quan

1
Mặc dù số (từ COUNT(*)) dễ xử lý, thậm chí còn dễ dàng hơn để trả về sự tồn tại của một hàng hay không; nếu có một hàng ở đó thì nó tồn tại, nếu không có hàng thì không. (Bạn đã kiểm tra thất bại trong moveToFirst, vì vậy công việc sẽ được thực hiện tại thời điểm đó.)
dash-tom-bang

Vui lòng cập nhật mã của bạn để đóng con trỏ trước khi bạn trả về false.
Dave Thomas

43

Bạn có thể thử:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = bảng sẽ hữu ích tho
mafu

Nếu sử dụng C #, không sử dụng lệnh này trong a SQLiteReader reader = cmd.ExecuteReader();và thực hiện dt.Load(reader)(trong đó dtlà a DataTable). Tôi thấy nó đưa ra Object reference is not an instance of an objectngoại lệ này .Load()nếu bảng không được tìm thấy. Thay vào đó, sử dụng a SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); và làm adapter.Fill(ds), đâu dslà a DataSet. Sau đó, bạn có thể xem nếu ds.Tables.Count > 0return ds.Tables[0];nếu vậy (hoặc else return null). Sau đó, bạn có thể kiểm tra xem có DataTabletồn tại null, nếu dt.Rows != nullvà nếudt.Rows.Count>0
vapcguy

34

Sử dụng:

PRAGMA table_info(your_table_name)

Nếu bảng kết quả là trống thì your_table_namekhông tồn tại.

Tài liệu:

Lược đồ PRAGMA.table_info (tên bảng);

Pragma này trả về một hàng cho mỗi cột trong bảng được đặt tên. Các cột trong tập kết quả bao gồm tên cột, kiểu dữ liệu, liệu cột có thể là NULL hay không và giá trị mặc định cho cột. Cột "pk" trong tập kết quả bằng 0 đối với các cột không phải là một phần của khóa chính và là chỉ mục của cột trong khóa chính cho các cột là một phần của khóa chính.

Bảng có tên trong pragma của bảng_info cũng có thể là dạng xem.

Ví dụ đầu ra:

cid|name|type|notnull|dflt_value|pk
0|id|INTEGER|0||1
1|json|JSON|0||0
2|name|TEXT|0||0

Đây là một cách tuyệt vời để xác định xem một bảng có tồn tại trong Python không.
Michael Murphy

hoặc Mẫu Xamarin
SerenityNow

4
Đây là một cách tuyệt vời để có được các định nghĩa cột theo chương trình
w00t

33

Tên bảng SQLite không phân biệt chữ hoa chữ thường, nhưng so sánh thì phân biệt chữ hoa chữ thường. Để làm cho điều này hoạt động đúng trong mọi trường hợp bạn cần thêm COLLATE NOCASE.

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE

33

Nếu bạn gặp lỗi "bảng đã tồn tại", hãy thay đổi chuỗi SQL như dưới đây:

CREATE table IF NOT EXISTS table_name (para1,para2);

Bằng cách này bạn có thể tránh các ngoại lệ.



23

Nếu bạn đang sử dụng fmdb , tôi nghĩ bạn chỉ cần nhập FMDatabaseAdditions và sử dụng hàm bool:

[yourfmdbDatabase tableExists:tableName].

1
Đảm bảo bạn nhập "FMDatabaseAdditions.h" để sử dụng phương pháp này nếu không bạn sẽ tự hỏi tại sao họ lại xóa nó! :)
Sẽ

Mặc dù đây có thể là một câu trả lời chính xác, câu hỏi là về sqlite không phải là một thư viện cụ thể trong một ngôn ngữ cụ thể. Tôi nghĩ rằng câu trả lời nên là cung cấp mã sql, không phải là một cuộc gọi đến một trong những phương thức của thư viện
nacho4d

13

Đoạn mã sau trả về 1 nếu bảng tồn tại hoặc 0 nếu bảng không tồn tại.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"

1
Điều này sẽ vẫn không trả về nếu bảng không tồn tại, vì điều kiện nơi ngăn chặn bất kỳ kết quả nào.
David Gausmann

10

Lưu ý rằng để kiểm tra xem bảng có tồn tại trong cơ sở dữ liệu TEMP hay không, bạn phải sử dụng sqlite_temp_masterthay vì sqlite_master:

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';

9

Đây là chức năng mà tôi đã sử dụng:

Đưa ra một đối tượng SQLDatabase = db

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}

1
Đáng buồn là tôi đã phải sử dụng điều này trong ứng dụng Android của mình vì tôi thấy rằng các thiết bị Samsung không sử dụng cấu trúc bảng sqlite_master tiêu chuẩn mà mọi người khác đang làm việc.
Anthony Chuinard

7

Sử dụng mã này:

SELECT name FROM sqlite_master WHERE type='table' AND name='yourTableName';

Nếu số mảng trả về bằng 1 thì có nghĩa là bảng tồn tại. Nếu không thì nó không tồn tại.


4
class CPhoenixDatabase():
    def __init__(self, dbname):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def is_table(self, table_name):
        """ This method seems to be working now"""
        query = "SELECT name from sqlite_master WHERE type='table' AND name='{" + table_name + "}';"
        cursor = self.conn.execute(query)
        result = cursor.fetchone()
        if result == None:
            return False
        else:
            return True

Lưu ý: Hiện tại nó đang hoạt động trên máy Mac của tôi với Python 3.7.1


Điều này có vẻ sạch sẽ hơn tất cả các câu trả lời khác .. Cảm ơn bạn !!
Harsha Vardhan

Không hoạt động đối với tôi: phải xóa dấu ngoặc {} xung quanh tên_bảng, sau đó thì ổn.
Chuối

1
Đảm bảo table_namekhông được cung cấp từ nguồn không được sử dụng (như đầu vào của người dùng), nếu không, nó sẽ dễ bị tấn công SQL. Luôn luôn tốt hơn để sử dụng các tham số thay vì các kỹ thuật thao tác văn bản
astef

3

Sử dụng

SELECT 1 FROM table LIMIT 1;

để ngăn chặn tất cả các hồ sơ được đọc.


Điều này trả về NULL nếu bảng tồn tại nhưng không có bất kỳ bản ghi nào.
radiospiel

Nếu bảng không tồn tại, nó sẽ đưa ra một lỗi. Nắm bắt điều đó, và bạn biết nó không tồn tại.
luckydonald

sử dụng xử lý lỗi như kiểm soát dòng chảy thường không được coi là thực hành tốt nhất. Điều này có lẽ nên tránh.
Jeff Woodard

3

Bạn có thể viết truy vấn sau đây để kiểm tra sự tồn tại của bảng.

SELECT name FROM sqlite_master WHERE name='table_name'

Đây 'tên_bảng' là tên bảng của bạn những gì bạn đã tạo. Ví dụ

 CREATE TABLE IF NOT EXISTS country(country_id INTEGER PRIMARY KEY AUTOINCREMENT, country_code TEXT, country_name TEXT)"

và kiểm tra

  SELECT name FROM sqlite_master WHERE name='country'

6
Làm thế nào khác với câu trả lời topvote đã được chấp nhận từ 9 năm trước?
Kevin Van Dyck

3

Cách đáng tin cậy nhất mà tôi đã tìm thấy trong C # ngay bây giờ, sử dụng gói nuget sqlite-net-pcl mới nhất (1.5.231) đang sử dụng SQLite 3, như sau:

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}

2

Sử dụng một truy vấn CHỌN đơn giản là - theo tôi - khá đáng tin cậy. Hầu hết tất cả nó có thể kiểm tra sự tồn tại của bảng trong nhiều loại cơ sở dữ liệu khác nhau (SQLite / MySQL).

SELECT 1 FROM table;

Điều này có ý nghĩa khi bạn có thể sử dụng cơ chế đáng tin cậy khác để xác định xem truy vấn có thành công hay không (ví dụ: bạn truy vấn cơ sở dữ liệu qua QSqlQuery trong Qt ).


1

Hàm c ++ kiểm tra db và tất cả các cơ sở dữ liệu đính kèm về sự tồn tại của bảng và cột (tùy chọn).

bool exists(sqlite3 *db, string tbl, string col="1")
{
    sqlite3_stmt *stmt;
    bool b = sqlite3_prepare_v2(db, ("select "+col+" from "+tbl).c_str(),
    -1, &stmt, 0) == SQLITE_OK;
    sqlite3_finalize(stmt);
    return b;
}

Chỉnh sửa: Gần đây đã phát hiện ra hàm sqlite3_table_column_metadata. Vì thế

bool exists(sqlite3* db,const char *tbl,const char *col=0)
{return sqlite3_table_column_metadata(db,0,tbl,col,0,0,0,0,0)==SQLITE_OK;}

bảng boolean tĩnh công khaiExists (cơ sở dữ liệu SQLiteDatabase, chuỗi tên bảng) {return cơ sở dữ liệu }
nick

Cách rất không hiệu quả và rủi ro vì nối chuỗi có thể kết thúc với mọi thứ.
Andrea Moro

0

Đây là mã của tôi cho SQLite Cordova:

get_columnNames('LastUpdate', function (data) {
    if (data.length > 0) { // In data you also have columnNames
        console.log("Table full");
    }
    else {
        console.log("Table empty");
    }
});

Và một cái khác:

function get_columnNames(tableName, callback) {
    myDb.transaction(function (transaction) {
        var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
        transaction.executeSql(query_exec, [], function (tx, results) {
            var columnNames = [];
            var len = results.rows.length;
            if (len>0){
                var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
                for (i in columnParts) {
                    if (typeof columnParts[i] === 'string')
                        columnNames.push(columnParts[i].split(" ")[0]);
                };
                callback(columnNames);
            }
            else callback(columnNames);
        });
    });
}

0

Tôi nghĩ rằng tôi đã đặt 2 xu của mình cho cuộc thảo luận này, ngay cả khi nó khá cũ .. Truy vấn này trả về vô hướng 1 nếu bảng tồn tại và 0 nếu không.

select 
    case when exists 
        (select 1 from sqlite_master WHERE type='table' and name = 'your_table') 
        then 1 
        else 0 
    end as TableExists

0

Bảng tồn tại hoặc không có trong cơ sở dữ liệu trong swift

func tableExists(_ tableName:String) -> Bool {
        sqlStatement = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(tableName)'"
        if sqlite3_prepare_v2(database, sqlStatement,-1, &compiledStatement, nil) == SQLITE_OK {
            if sqlite3_step(compiledStatement) == SQLITE_ROW {
                return true
            }
            else {
                return false
            }
        }
        else {
            return false
        }
            sqlite3_finalize(compiledStatement)
    }
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.