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

How do I check in SQLite whether a table exists?

提问人:PoorLuzer 提问时间:10/21/2009 最后编辑:Peter MortensenPoorLuzer 更新时间:7/10/2023 访问量:591364

问:

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

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

原因是这样的:

在我的程序中,我需要创建并填充一些表(如果它们尚不存在)。

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

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

还是我的方法有意义?

SQLite的

评论

0赞 Erik Bachmann 9/16/2023
看到 Ravens 评论似乎真的将结果减少到布尔结果(0 或 1,仅此而已)SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type="table" AND name="table_name");

答:

49赞 Anton Gogolev 10/21/2009 #1

请参阅 SQLite FAQ 中的 (7) 如何列出 SQLite 数据库中包含的所有表/索引

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
56赞 Galwegian 10/21/2009 #2

您可以尝试:

SELECT name FROM sqlite_master WHERE name='table_name'

评论

9赞 mafu 3/30/2012
type = table 会很有用
0赞 vapcguy 11/17/2016
如果使用 C#,请不要在 a 中使用此命令,并执行 a (where is a )。我发现如果找不到表,它会给出这个异常。相反,请使用 a 和 do ,其中 是 .然后,您可以查看是否以及是否是(或)。然后你可以检查它是 、 if 和 ifSQLiteReader reader = cmd.ExecuteReader();dt.Load(reader)dtDataTableObject reference is not an instance of an object.Load()SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); adapter.Fill(ds)dsDataSetds.Tables.Count > 0return ds.Tables[0];else return nullDataTablenulldt.Rows != nulldt.Rows.Count>0
1214赞 PoorLuzer 10/22/2009 #3

我错过了那个FAQ条目。

无论如何,为了将来参考,完整的查询是:

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

其中是要检查的表的名称。{table_name}

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

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

评论

9赞 Pawel Veselov 1/3/2012
SQLite文档中的哪些文档涵盖了这些系统表?
34赞 Bryan Oakley 1/12/2012
@Pawel Veselov:标题为“SQLite数据库的文件格式”的部分:sqlite.org/fileformat2.html
1赞 CenterOrbit 7/9/2012
如果您使用的是 Adobe Air SQLite,这不起作用,对于您在 AS3/Air 中编程的情况,这里有一个(更好的)替代方案:stackoverflow.com/questions/4601707/...
19赞 PatchyFog 12/19/2012
但是,这不适用于 TEMP 表。TEMP 表位于“sqlite_temp_master”中。
3赞 Igor Levicki 8/28/2022
从 SQLite 版本 3.33.0 开始,该表的新名称为 .旧名称仍然有效,但答案可能应该更新以提及新名称。sqlite_schema
661赞 arthur johnston 3/6/2011 #4

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

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

同样,仅当表存在时,才能使用以下方法删除该表:

drop table if exists TableName

评论

14赞 lowtech 12/2/2013
索引也有类似的构造:如果不存在,则创建索引 TableName_col1 TableName(col1)
41赞 Dagrooms 6/17/2015
这不应该是公认的答案,但如果问题的措辞不同,就会被接受。OP 没有询问如何在删除或创建之前检查表。如果必须查询可能不存在的表,该怎么办?这就是我现在面临的问题,公认的答案在这个一般问题陈述中效果最好。这是一个很好的快速选择。
13赞 pacheco 8/8/2011 #5

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

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

评论

2赞 David Gausmann 4/25/2018
如果表不存在,这仍然不会返回任何内容,因为 where 条件会阻止任何结果。
221赞 Stephen Quan 1/12/2012 #6

一种变体是使用 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;
}

评论

43赞 PatchyFog 12/18/2012
我相信“SELECT 1”会更快。
0赞 Semyon Danilov 1/24/2014
为什么cursor.getInt(0)等于数据库中的记录计数?
3赞 Stephen Quan 1/24/2014
我们正在计算 TABLE 在 sqlite 模式中出现的次数。计数为 0 表示该表不存在。计数为 1 表示该表确实存在。这是仅有的两个预期计数值。
1赞 dash-tom-bang 7/27/2016
虽然数字 (from ) 很容易处理,但返回是否存在行就更容易了;如果那里有一行,那么它就存在,如果没有行,它就不存在。(您已经在 moveToFirst 中检查了失败,因此此时工作将完成。COUNT(*)
6赞 Raven 3/30/2022
SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type="table" AND name="table_name")似乎真的将结果减少到布尔结果(0 或 1,仅此而已)
24赞 user655489 4/6/2012 #7

如果您使用的是 fmdb,我认为您可以导入 FMDatabaseAdditions 并使用 bool 函数:

[yourfmdbDatabase tableExists:tableName].

评论

1赞 Will 3/18/2015
确保导入“FMDatabaseAdditions.h”以使用此方法,否则您会想知道为什么他们删除了它!:)
1赞 nacho4d 4/5/2016
虽然这可能是一个正确的答案,但问题是关于sqlite,而不是特定语言的特定库。我认为答案应该是提供sql代码,而不是调用库的方法之一
3赞 Grz 4/11/2012 #8

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

SELECT 1 FROM table;

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

9赞 DroidGrailer 6/12/2012 #9

这是我使用的函数:

给定 SQLDatabase 对象 = db

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

评论

1赞 Anthony Chuinard 6/14/2015
可悲的是,我不得不在我的 Android 应用程序中使用它,因为我发现三星设备不使用其他人正在使用的标准sqlite_master表结构。
7赞 asmad 12/20/2013 #10

使用以下代码:

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

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

38赞 Brice M. Dempsey 2/22/2014 #11

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

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE
11赞 Scott Deerwester 4/24/2014 #12

请注意,要检查 TEMP 数据库中是否存在表,必须使用 :sqlite_temp_mastersqlite_master

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';
39赞 Diego Vélez 9/30/2014 #13

用:

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

评论

0赞 Harish Ganesan 9/6/2022
另一种方法是使用 select * from pragma_table_list where name=“your_table_name”;这是 3.37 中 sqlite 中的新编译指示。sqlite.org/pragma.html#pragma_table_list
3赞 Franz Fahrenkrog Petermann 10/29/2014 #14

SELECT 1 FROM table LIMIT 1;

以防止读取所有记录。

评论

0赞 radiospiel 1/14/2015
如果表存在但没有任何记录,则返回 NULL。
0赞 luckydonald 7/2/2015
如果该表不存在,它将引发错误。抓住它,你就知道它不存在。
1赞 Jeff Woodard 10/4/2016
使用错误处理作为流控制通常不被视为最佳实践。这可能应该避免。
36赞 Rakesh Chaudhari 10/20/2015 #15

如果出现“表已存在”错误,请在 SQL 字符串中进行更改,如下所示:

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

这样可以避免异常。

0赞 Zappescu 2/3/2017 #16

这是我的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);
        });
    });
}
1赞 Piotr Rodak 6/11/2017 #17

我以为我会把我的 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
6赞 AnKr 8/2/2018 #18

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

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'

评论

8赞 Kevin Van Dyck 8/2/2018
这与 9 年前已经接受的最高票答案有何不同?
7赞 Douglas Goodall 11/15/2018 #19
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

注意:这现在可以在我的装有 Python 3.7.1 的 Mac 上运行

评论

0赞 Banana 8/4/2019
对我不起作用:必须擦除table_name周围的 {} 括号,然后就可以了。
1赞 astef 8/28/2019
确保不是从未受限制的源(如用户输入)提供的,否则它很容易受到 SQL 注入的影响。最好使用参数而不是文本操作技术table_name
3赞 Matthew Joughin 1/19/2019 #20

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

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}
0赞 Srinivasan_iOS 6/1/2019 #21

在 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)
    }
0赞 NoComprende 10/23/2019 #22

C++ 函数检查数据库和所有附加的数据库是否存在表和(可选)列。

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

评论

0赞 nick 11/17/2019
public static boolean tableExists(SQLiteDatabase database, String tableName){ return database.rawQuery(“SELECT name FROM sqlite_master WHERE type='table' AND name='” + tableName + “'”, null).moveToFirst();
0赞 Andrea Moro 5/6/2020
非常低效和冒险的方式,因为字符串连接可能最终会导致一切。
0赞 Shivam Pokhriyal 3/18/2021 #23

您还可以使用数据库元数据来检查表是否存在。

DatabaseMetaData md = connection.getMetaData();
ResultSet resultSet = md.getTables(null, null, tableName, null);
if (resultSet.next()) {
    return true;
}

评论

1赞 birgersp 5/5/2021
应该在返回之前关闭resultSet
1赞 sn0wbl1nd 3/21/2021 #24

我的首选方法:

SELECT "name" FROM pragma_table_info("table_name") LIMIT 1;

如果获得行结果,则表示该表存在。这(对我来说)比检查更好,因为它还将检查附加数据库和临时数据库。sqlite_master

0赞 yuviscor 4/8/2021 #25

如果您使用 python 文件运行它并显然使用 sqlite3。打开命令提示符或 bash 无论您正在使用什么,都使用

  1. python3 file_name.py编写 SQL 代码的第一个。
  2. 然后file_name.db运行 sqlite3
  3. .table 此命令将提供表(如果存在)。
0赞 StickySli 4/8/2022 #26

我想补充迭戈·贝莱斯(Diego Vélez)关于该声明的回答。PRAGMA

https://sqlite.org/pragma.html 我们得到了一些有用的函数,这些函数可以返回有关我们数据库的信息。 在这里,我引用以下内容:

例如,可以使用 index_info 编译指示读取有关索引中列的信息,如下所示:

PRAGMA index_info('idx52');

或者,可以使用以下方法读取相同的内容:

SELECT * FROM pragma_index_info('idx52');

表值函数格式的优点是查询可以只返回 PRAGMA 列的子集,可以包含 WHERE 子句,可以使用聚合函数,并且表值函数可以只是联接中的多个数据源之一。

迭戈的回答给出了一个选项,但这在您的其他查询中没有多大用处。PRAGMA table_info(table_name)

因此,要回答 OPs 问题并改进 Diegos 答案,您可以这样做

SELECT * FROM pragma_table_info('table_name');

甚至更好,

SELECT name FROM pragma_table_list('table_name');

如果你想模仿 PoorLuzers 的最高票答案。

0赞 Mohamed Reda 6/10/2022 #27

如果你处理 Big Table,我用 Python 和 Sqlite 做了一个简单的 hack,你可以用任何其他语言提出类似的想法

第 1 步:不要在 create table 命令中使用(如果不存在)

如果您运行此命令,您可能知道,如果您之前已经创建了表,并且想要再次创建它,则该命令将出现异常,但这将引导我们进入第二步。

第 2 步:使用 try 和 except (或其他语言的 try 和 catch) 来处理最后一个异常

在这里,如果您之前没有创建表,则 try 用例将继续,但如果您已经创建了,则可以将 do your process 置于 except 大小写,您将知道您已经创建了表。

代码如下:

def create_table():
    con = sqlite3.connect("lists.db")
    cur = con.cursor()
    try:
        cur.execute('''CREATE TABLE UNSELECTED(
        ID INTEGER PRIMARY KEY)''')
        print('the table is created Now')

    except sqlite3.OperationalError:
        print('you already created the table before')
    con.commit()
    cur.close()
0赞 Luis Tejeda 6/29/2022 #28

你可以使用一个简单的方法,我在 C# 和 Xamarin 中使用这个方法,

public class LoginService : ILoginService
{
    private SQLiteConnection dbconn; 
}

在登录服务类中,我有很多方法可以访问SQLite中的数据,我将数据存储到一个表中,登录页面 它仅在用户未登录时显示。

为此,我只需要知道表是否存在,在这种情况下,如果它存在,那是因为它有数据

public int ExisteSesion()
    {
        var rs = dbconn.GetTableInfo("Sesion");
        return rs.Count;
    }

如果该表不存在,则仅返回 0,如果该表存在,则因为它有数据,并且返回它拥有的总行数。

在模型中,我指定了表必须接收的名称,以确保其正确操作。

    [Table("Sesion")]
public class Sesion
{
    [PrimaryKey]
    public int Id { get; set; }
    public string Token { get; set; }
    public string Usuario { get; set; }

}
3赞 Abednego Nasila 8/1/2022 #29

R DBI 包中的函数为 R 程序员简化了这个问题。请参阅以下示例:dbExistsTable()

library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
# let us check if table iris exists in the database
dbExistsTable(con, "iris")
### returns FALSE

# now let us create the table iris below,
dbCreateTable(con, "iris", iris)
# Again let us check if the table iris exists in the database,
dbExistsTable(con, "iris")
### returns TRUE 
-1赞 Brian Olson 2/9/2023 #30

查看 C++ 中的“尝试 - 抛出 - 捕获”结构。大多数其他编程语言都有类似的结构来处理错误。

评论

0赞 Community 2/17/2023
正如目前所写的那样,你的答案尚不清楚。请编辑以添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以在帮助中心找到有关如何写出好答案的更多信息。
0赞 Mark 7/10/2023 #31

如前所述,您可以使用以下查询查找表是否存在

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

但是,此查询将仅搜索架构main.sqlite_master

如果有一个或多个附加数据库使用

ATTACH DATABASE AS schema-name

然后,在附加的架构中将找不到表

要知道表是否存在于“main”以外的模式中,您需要遍历所有模式,例如 schema-name.sqlite_master。

为了解决这个问题,我看到 2 个选项

  1. 记住附加的数据库架构名称并循环访问这些名称
  2. 使用 sqlite 本机功能查找所有附加的数据库并遍历此列表

可以使用以下方法完成第二个选项

select * from pragma_database_list

这将返回 order、schema-name 和 DATABASE,然后您可以遍历所有 {schema-name}.sqlite_master 并查找是否存在表以及在哪个架构中(可能存在多个) ref: https://www.sqlite.org/dbpage.html#using_sqlite_dbpage_on_attach_ed_databases 是唯一的引用。我可以找到这一点,因此无法看到这是否是sqlite功能的维护部分