【问题标题】:How do I check in SQLite whether a table exists?如何在 SQLite 中检查表是否存在?
【发布时间】:2022-01-21 14:26:15
【问题描述】:

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

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

原因是这样的:

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

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

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

或者我的方法有意义吗?

【问题讨论】:

  • 如果 select 中的表不存在,SQLite 会抛出异常。根本不需要任何花哨的工作。
  • @NoChance 会的,但其他任何事情都会如此。这有点像闭着眼睛向前行驶,看看那棵树是否真的在那里,你会发现一种或另一种方式:)
  • @randomsock,我不知道 sqlite 的约定是什么,但请求宽恕比请求许可更像是 Pythonic。即捕获异常而不是使用条件。
  • @Eric 截至目前,该问题不涉及 Python,但假设它涉及,错误是通用的sqlite3.OperationalError,因此您必须解析错误消息以确保它是例如创建表时显示“表 TABLE_NAME 已存在”消息,如果没有,请重新提出错误,我认为无法保证错误的措辞不会改变。

标签: sqlite


【解决方案1】:

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

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

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

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

参考文档部分:Database File Format. 2.6. Storage Of The SQL Database Schema

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

【讨论】:

  • 哪些 SQLite 文档涵盖了这些系统表?
  • @Pawel Veselov:标题为“SQLite 数据库的文件格式”的部分:sqlite.org/fileformat2.html
  • 但是,这不适用于 TEMP 表。 TEMP 表位于“sqlite_temp_master”中。
  • 这是否返回布尔值?如果表存在或不存在,它会返回什么?
  • @Dagrooms 这将返回具有指定名称的表列表;也就是说,游标的计数为 0(不存在)或计数为 1(存在)。
【解决方案2】:

如果您使用的是 SQLite 3.3+ 版本,您可以轻松地创建一个表:

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

同样的,你可以删除一个表,只有当它存在时使用:

drop table if exists TableName

【讨论】:

  • 索引也有类似的构造:如果TableName(col1)上不存在TableName_col1,则创建索引
  • 这不应该是公认的答案,但如果问题的措辞不同的话。 OP 在删除或创建之前没有询问如何检查表。如果您必须查询一个可能不存在的表怎么办?这是我现在面临的问题,接受的答案在这个一般问题陈述中效果最好。这是一个很好的快速替代方案。
  • @Dagrooms,你可能是对的。虽然 OP 没有问这个,但我一直在寻找这个答案:)
【解决方案3】:

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

【讨论】:

  • 我相信“SELECT 1”会更快。
  • 为什么 cursor.getInt(0) 等于数据库中的记录数?
  • 我们正在计算 TABLE 在 sqlite 模式中出现的次数。计数为 0 表示该表不存在。计数为 1 表示该表确实存在。这是 count 仅有的两个预期值。
  • 虽然数字(来自COUNT(*))很容易处理,但返回是否存在行更容易;如果那里有一行那么它存在,如果没有行它不存在。 (您已经在 moveToFirst 中检查失败,因此工作将在那时完成。)
  • 请更新您的代码以在返回 false 之前关闭光标。
【解决方案4】:

你可以试试:

SELECT name FROM sqlite_master WHERE name='table_name'

【讨论】:

  • type = table 会很有用
  • 如果使用 C#,请不要在 SQLiteReader reader = cmd.ExecuteReader(); 中使用此命令并执行 dt.Load(reader)(其中 dtDataTable)。我发现如果找不到表,它会在.Load() 上给出这个Object reference is not an instance of an object 异常。相反,使用SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); 并执行adapter.Fill(ds),其中dsDataSet。然后您可以查看ds.Tables.Count > 0return ds.Tables[0]; 是否是这样(或else return null)。然后你可以检查DataTable 是否是null,如果是dt.Rows != null,如果是dt.Rows.Count>0
【解决方案5】:

请参阅 SQLite 常见问题解答中的 (7) How do I list all tables/indices contained in an SQLite database

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;

【讨论】:

    【解决方案6】:

    用途:

    PRAGMA table_info(your_table_name)
    

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

    文档:

    PRAGMA schema.table_info(table-name);

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

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

    示例输出:

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

    【讨论】:

    • 这是确定 Python 中是否存在表的好方法。
    • 或 Xamarin 表单
    • 这是以编程方式获取列定义的好方法
    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

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

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

      这样可以避免异常。

      【讨论】:

        【解决方案9】:

        如果你使用fmdb,我想你可以import FMDatabaseAdditions并使用bool函数:

        [yourfmdbDatabase tableExists:tableName].
        

        【讨论】:

        • 确保您导入“FMDatabaseAdditions.h”以使用此方法,否则您会想知道他们为什么要删除它! :)
        • 虽然这可能是一个正确的答案,但问题是关于 sqlite 而不是特定语言的特定库。我认为答案应该是提供sql代码,而不是调用库的方法之一
        【解决方案10】:

        如果表存在则返回 1,如果表不存在则返回 0。

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

        【讨论】:

        • 如果表不存在,这仍然不会返回任何内容,因为 where 条件会阻止任何结果。
        【解决方案11】:

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

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

        【讨论】:

          【解决方案12】:

          这是我使用的函数:

          给定一个 SQLDatabase 对象 = db

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

          【讨论】:

          • 很遗憾,我不得不在我的 Android 应用程序中使用它,因为我发现三星设备不使用其他人都在使用的标准 sqlite_master 表结构。
          【解决方案13】:

          使用此代码:

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

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

          【讨论】:

            【解决方案14】:
            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 上运行

            【讨论】:

            • 这看起来比所有其他答案都干净.. 谢谢!!
            • 对我不起作用:必须删除 table_name 周围的 {} 括号,然后就可以了。
            • 确保table_name 不是来自不受信任的来源(如用户输入),否则容易受到 SQL 注入的攻击。使用参数而不是文本操作技术总是更好
            【解决方案15】:

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

            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'
            

            【讨论】:

            • 这与 9 年前已经接受的最高投票答案有何不同?
            【解决方案16】:

            使用

            SELECT 1 FROM table LIMIT 1;
            

            防止所有记录被读取。

            【讨论】:

            • 如果表存在但没有任何记录,则返回 NULL。
            • 如果表不存在,会报错。抓住它,你就会知道它不存在。
            • 使用错误处理作为流控制通常不被认为是最佳实践。应该避免这种情况。
            【解决方案17】:

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

            SELECT 1 FROM table;
            

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

            【讨论】:

              【解决方案18】:

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

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

              【讨论】:

                【解决方案19】:

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

                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 database, String tableName){ return database.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'", null) .moveToFirst(); }
                • 非常低效且危险的方式,因为字符串连接可能会导致所有问题。
                【解决方案20】:

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

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

                【讨论】:

                • 应该在返回之前关闭resultSet
                【解决方案21】:

                我的首选方法:

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

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

                【讨论】:

                  【解决方案22】:

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

                  【讨论】:

                    【解决方案23】:

                    我想我会把我的 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
                    

                    【讨论】:

                      【解决方案24】:

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

                      【讨论】:

                        【解决方案25】:

                        如果您使用 python 文件运行它并且显然使用 sqlite3。打开命令提示符或 bash 你正在使用的任何东西

                        1. python3 file_name.py首先在其中编写您的 sql 代码。
                        2. 然后运行 ​​sqlite3 file_name.db
                        3. .table 如果表格存在,此命令将给出表格。

                        【讨论】:

                          猜你喜欢
                          • 2014-10-24
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2017-02-16
                          • 1970-01-01
                          • 2021-10-06
                          相关资源
                          最近更新 更多