如何在SQLite中检查表是否存在?


893

我如何可靠在SQLite中检查是否存在特定的用户表?

我不是在要求不可靠的方法,例如检查表上的“ select *”是否返回错误(这甚至是个好主意吗?)。

原因是这样的:

在我的程序中,我需要创建然后填充一些表(如果还不存在)。

如果它们已经存在,则需要更新一些表。

我是否应该采取其他途径来表示已经建立了相关表-例如,通过在磁盘上的程序初始化/设置文件中创建/放置/设置某个标志,等等?

还是我的方法有意义?


如果选择中的表不存在,SQLite将引发异常。根本不需要任何其他花哨的工作。
NoChance

34
@NoChance可以,但是其他任何事情也可以。这有点像通过闭上眼睛向前看看那棵树是否真的在那里,您会发现一种或另一种方法:)
randomsock 17/02/11

@randomsock,一个很好的例子,但有点吓人,特别是如果这辆车是我的车……
NoChance 17-02-27

@randomsock,我不知道什么是sqlite约定,但是请求宽恕比允许更多Python风格。即捕获异常,而不是使用条件。
埃里克(Eric)

1
@Eric到目前为止,该问题不涉及Python,但是假设它涉及该错误sqlite3.OperationalError,那么该错误是一个通用错误,因此您必须分析错误消息以确保创建时该错误消息例如为“ table TABLE_NAME has exist”一个表,如果没有,则重新引发错误,我认为不能保证错误的措词不会改变。
Markus von Broady

Answers:


1019

我错过了该常见问题解答条目。

无论如何,完整的查询是:

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

{table_name}要检查的表的名称在哪里。

供参考的文档部分:数据库文件格式。2.6。SQL数据库架构的存储

  • 这将返回具有指定名称的表的列表;也就是说,游标的计数为0(不存在)或计数为1(存在)

7
哪个SQLite文档涵盖了这些系统表?
Pawel Veselov

29
@Pawel Veselov:标题为“ SQLite数据库的文件格式”的部分:sqlite.org/fileformat2.html
Bryan Oakley,

14
但是,这不适用于TEMP表。TEMP表位于“ sqlite_temp_master”中。
PatchyFog 2012年

11
这会返回布尔值吗?如果该表存在或不存在,它将返回什么?
Dagrooms

8
@Dagrooms这将返回具有指定名称的表的列表;也就是说,游标的计数为0(不存在)或计数为1(存在)。
Rein S

555

如果您使用的是SQLite 3.3+版本,则可以使用以下命令轻松创建表:

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

以同样的方式,您只能使用以下方法删除表:

drop table if exists TableName

3
请注意,该create table语句不完整(缺少表列规范)。
埃里克·普拉顿

11
索引也有类似的构造:如果TableName(col1)上的TableName_col1不存在,则创建索引
lowtech 2013年

26
这不应该是公认的答案,但是如果问题的措词不同。OP并未询问在删除或创建表之前如何检查表。如果您必须查询一个可能不存在的表怎么办?这是我现在面临的问题,在此一般性问题陈述中,可接受的答案最有效。这是一个很好的快速选择。
Dagrooms

@Dagrooms,您可能是正确的。尽管OP并没有提出这个问题,但我一直在寻找这个答案:)
earik87

169

一种变化是使用SELECT COUNT(*)而不是SELECT NAME,即

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

如果表不存在,则返回0,否则返回1。这可能在您的编程中很有用,因为数值结果更快/更容易处理。以下内容说明了如何在Android中使用带参数的SQLiteDatabase,Cursor,rawQuery进行此操作。

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
我相信“ SELECT 1”会更快。
PatchyFog 2012年

为什么cursor.getInt(0)等于数据库中的记录数?
Semyon Danilov

1
我们正在计算TABLE在sqlite模式中出现的次数。计数为0表示该表不存在。计数为1表示该表确实存在。这是count的两个唯一期望值。
Stephen Quan

1
虽然数字(from COUNT(*))很容易处理,但返回行是否存在甚至更容易;如果有一行,那么就存在,如果没有一行,就没有。(您已经在moveToFirst中检查是否有故障,因此该工作将在此时完成。)
dash-tom-bang

在返回false之前,请更新代码以关闭游标。
戴夫·托马斯

43

您可以尝试:

SELECT name FROM sqlite_master WHERE name='table_name'

4
类型=表将是有用的
马夫

如果使用C#,请不要在a中使用此命令,而是SQLiteReader reader = cmd.ExecuteReader();执行a dt.Load(reader)(其中dtDataTable)。我发现如果找不到该表,它会给出此Object reference is not an instance of an object异常.Load()。而是使用a SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); 和do adapter.Fill(ds),其中dsDataSet。然后,您可以看到,如果ds.Tables.Count > 0return ds.Tables[0];如果是这样(或else return null)。然后,您可以检查是否DataTablenulldt.Rows != nulldt.Rows.Count>0
vapcguy

34

采用:

PRAGMA table_info(your_table_name)

如果结果表为空your_table_name,则不存在。

说明文件:

PRAGMA schema.table_info(表名);

该编译指示为命名表中的每一列返回一行。结果集中的列包括列名称,数据类型,该列是否可以为NULL以及该列的默认值。对于不属于主键的列,结果集中的“ pk”列为零,对于属于主键的列,该列的索引为主键中列的索引。

table_info杂注中命名的表也可以是视图。

输出示例:

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

这是确定表是否在Python中存在的好方法。
Michael Murphy

或Xamarin形式
SerenityNow

4
这是一种以编程方式获取列定义的好方法
w00t

33

SQLite表名称不区分大小写,但是默认情况下比较是区分大小写的。为了使它在所有情况下都能正常工作,您需要添加COLLATE NOCASE

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

33

如果收到“表已存在”错误,请在SQL字符串中进行如下更改:

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

这样您可以避免异常。



23

如果您使用FMDB,我觉得你可以导入FMDatabaseAdditions并使用布尔函数:

[yourfmdbDatabase tableExists:tableName].

1
确保导入“ FMDatabaseAdditions.h”以使用此方法,否则您会奇怪为什么他们将其删除了!:)
2015年

尽管这可能是正确的答案,但问题是关于sqlite而不是特定语言的特定库。我认为答案应该是提供sql代码,而不是调用该库的方法之一
nacho4d 2016年

13

如果表存在,则以下代码返回1;如果表不存在,则返回0。

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

1
如果表不存在,这仍然不会返回任何内容,因为where条件会阻止任何结果。
David Gausmann '18

10

请注意,要检查TEMP数据库中是否存在表,必须使用sqlite_temp_master代替sqlite_master

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

9

这是我使用的功能:

给定一个SQLDatabase Object = db

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

1
不幸的是,我发现三星设备没有使用其他所有人都在使用的标准sqlite_master表结构,因此我不得不在Android应用程序中使用它。
安东尼·丘纳德

7

使用此代码:

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

如果返回的数组计数等于1,则表示该表存在。否则它不存在。


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

注意:现在可以在Mac上使用Python 3.7.1的计算机上使用


这看起来比所有其他答案更干净。谢谢!
Harsha Vardhan

对我不起作用:必须删除table_name周围的{}括号,然后再行。
香蕉

1
确保table_name未提供来自未发布源的信息(例如用户输入),否则它将容易受到SQL注入的攻击。始终最好使用参数代替文本操作技术
astef


3

您可以编写以下查询来检查表是否存在。

SELECT name FROM sqlite_master WHERE name='table_name'

这里的“ table_name”是您创建的表名。例如

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

并检查

  SELECT name FROM sqlite_master WHERE name='country'

6
这与9年前已被接受的最高投票答案有何不同?
凯文·范戴克

3

我现在使用最新的sqlite-net-pcl nuget软件包(1.5.231)(使用SQLite 3)在C#中找到的最可靠的方法如下:

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

2

我认为,使用简单的SELECT查询非常可靠。最重要的是,它可以检查许多不同数据库类型(SQLite / MySQL)中表的存在。

SELECT 1 FROM table;

当您可以使用其他可靠的机制确定查询是否成功(例如,通过Qt中的 QSqlQuery查询数据库)时,这才有意义。


1

c ++函数检查db和所有附加数据库中是否存在table和(可选)列。

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

编辑:最近发现了sqlite3_table_column_metadata函数。因此

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

public static boolean tableExists(SQLiteDatabase数据库,字符串tableName){返回database.rawQuery(“ SELECT name from sqlite_master WHERE type ='table'AND name ='” + tableName +“'”,null).moveToFirst(); }
尼克,

字符串连接可能最终导致所有事情,效率非常低下,也很冒险。
Andrea Moro

0

这是我的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");
    }
});

而另一个:

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

我以为我会在讨论中投入2美分,即使它已经很老了。如果表存在,此查询将返回标量1,否则返回0。

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

0

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)
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.