检查数据库中是否存在表

内置的 DatabaseTableExists 函数允许通过其名称检查表是否存在。

bool DatabaseTableExists(int database, const string table)

数据库描述符和表名在参数中指定。如果表存在,函数调用的结果为 true

我们通过添加 hasTable 方法来扩展 DBSQLite 类。

class DBSQLite
{
   ...
   bool hasTable(const string tableconst
   {
      return DatabaseTableExists(handletable);
   }

DBcreateTable.mq5 脚本将检查表是否已出现。

void OnStart()
{
   DBSQLite db(Database);
   if(db.isOpen())
   {
      PRTF(db.execute(StringFormat("CREATE TABLE %s (msg text)"Table)));
      PRTF(db.hasTable(Table));
   }
}

再次强调,不必担心在尝试重新创建时可能收到错误。这丝毫不影响表的存在性。

database error, table table1 already exists
db.execute(StringFormat(CREATE TABLE %s (msg text),Table))=false / DATABASE_ERROR(5601)
db.hasTable(Table)=true / ok

由于我们正在编写一个通用的辅助类 DBSQLite,我们将在其中提供删除表的机制。SQL 为此目的提供了 DROP 命令。

class DBSQLite
{
   ...
   bool deleteTable(const string nameconst
   {
      const static string query = "DROP TABLE '%s';";
      if(!DatabaseTableExists(handlename)) return true;
      if(!DatabaseExecute(handleStringFormat(queryname))) return false;
      return !DatabaseTableExists(handlename)
         && ResetLastErrorOnCondition(_LastError == DATABASE_NO_MORE_DATA);
   }
   
   static bool ResetLastErrorOnCondition(const bool cond)
   {
      if(cond)
      {
         ResetLastError();
         return true;
      }
      return false;
   }

在执行查询之前,我们检查表是否存在,如果不存在则立即退出。

执行查询后,我们通过再次调用 DatabaseTableExists 来额外检查表是否已被删除。由于表不存在将用 DATABASE_NO_MORE_DATA 错误代码进行标记,这是此方法的预期结果,因此我们使用 ResetLastErrorOnCondition 清除该错误代码。

使用 SQL 的功能来排除删除不存在表的尝试可能更有效:只需在查询中添加短语 "IF EXISTS" 即可。因此,deleteTable 方法的最终版本得以简化:

   bool deleteTable(const string nameconst
   {
      const static string query = "DROP TABLE IF EXISTS '%s';";
      return DatabaseExecute(handleStringFormat(queryname));
   }

你可以尝试编写一个用于删除表的测试脚本,但小心不要错误地删除了工作表。表会连同所有数据立即删除,不会提示确认,也无法恢复。对于重要项目,请保留数据库备份。