【问题标题】:How can I programmatically determine if a table exists within a SQL Server CE database?如何以编程方式确定 SQL Server CE 数据库中是否存在表?
【发布时间】:2016-03-14 16:27:25
【问题描述】:

当我的.sdf 文件中只有一个表时,这段代码运行良好:

const string sdfPath = @"\Program Files\duckbilled\Platypus.sdf";
string dataSource = string.Format("Data Source={0}", sdfPath);

if (!File.Exists(sdfPath))
{
    using (var engine = new SqlCeEngine(dataSource))
    {
        engine.CreateDatabase();
    }
    using (var connection = new SqlCeConnection(dataSource))
    {
        connection.Open();
        using (var command = new SqlCeCommand())
        {
            command.Connection = connection;
            command.CommandText =
                "CREATE TABLE Platydudes (Id int NOT NULL, BillSize smallint NOT NULL, Description nvarchar(255)";
            command.ExecuteNonQuery();
        }
    }
}

...但现在我需要知道的不是数据库文件(Platypus.sdf)是否存在,而是该表/文件中是否存在特定的(例如Platydudes) .有没有办法确定?

更新

查询中的“IF NOT EXISTS”子句会导致运行时异常。这段代码:

using (var connection = new SqlCeConnection(dataSource))
{
    connection.Open();
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "IF NOT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'InventoryItems') " +
            "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
        command.ExecuteNonQuery();
    }
}

...导致抛出此异常:解析查询时出错。 [令牌行号=1,令牌行偏移量=1,错误令牌=IF]

因此,查询解析器显然不需要“IF”业务。如果表不存在,是否有另一种方法只创建表?还是我应该每次都先删除表然后重新创建它? IOW,我应该这样做吗:

using (var connection = new SqlCeConnection(dataSource))
{
    connection.Open();
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "DELETE InventoryItems";
        command.ExecuteNonQuery();
    }
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
        command.ExecuteNonQuery();
    }
}

?

更新 2

在第一次更新中回答我上面的问题:不!如果我这样做,我会在第二次调用 .ExecuteNonQuery() 时得到“指定的表已经存在”。

更新 3

回应 Shiva 对我的回答的评论:

这(重用命令对象)以同样的方式失败(“表已经存在”):

using (var command = new SqlCeCommand())
{
    command.Connection = connection;
    command.CommandText = "DELETE InventoryItems";
    command.ExecuteNonQuery();
    command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
    command.ExecuteNonQuery();
}

【问题讨论】:

  • DELETE InventoryItems 不会删除表,它只是删除所有行。 DROP TABLE InventoryItems 将删除表本身。
  • 哦,是的,我知道;大脑冻结!

标签: c# sql-server-ce compact-framework windows-ce windows-embedded-compact


【解决方案1】:

SQL Compact 不太喜欢 SQL 语句中的逻辑,因此 Shiva 的回答可能不会通过解析器。不过,他走在正确的道路上。您可以分两步完成:

这是OpenNETCF ORM 的 SQL Compact 实现中的 TableExists 方法:

public override bool TableExists(string tableName)
{
    var connection = GetConnection(true);
    try
    {
        using (var command = GetNewCommandObject())
        {
            command.Transaction = CurrentTransaction as SqlCeTransaction;
            command.Connection = connection;
            var sql = string.Format(
                    "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", 
                     tableName);
            command.CommandText = sql;
            var count = Convert.ToInt32(command.ExecuteScalar());

            return (count > 0);
        }
    }
    finally
    {
        DoneWithConnection(connection, true);
    }
}

显然,对于您的情况,它并不完整,但它很容易理解。 CurrentTransaction 很容易为空。 GetNewCommandObject 只返回一个新的 SqlCeCommand 实例。 GetConnection 可以简单地返回一个新的 SqlCeConnection 实例。 DoneWithConnection 可能是一个 NOP。基本上这些都是处理 ORM 支持过多的后备存储的事实。您需要的核心信息是我传入的 SQL 以及我如何确定真假返回。

我(未经编译器测试)对结果方法的猜测是这样的:

public bool TableExists(SqlCeConnection connection, string tableName)
{
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        var sql = string.Format(
                "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", 
                 tableName);
        command.CommandText = sql;
        var count = Convert.ToInt32(command.ExecuteScalar());
        return (count > 0);
    }
}

【讨论】:

  • 我认为您应该在var count = Convert.ToInt32(command.ExecuteScalar()); 之前添加connection.Open();。我的就是这样工作的。
【解决方案2】:

如果你想检查一个表是否存在,你必须使用TABLE_SCHEMA

IF (EXISTS (SELECT * 
             FROM INFORMATION_SCHEMA.TABLES 
             WHERE TABLE_SCHEMA = 'TheSchema' 
             AND  TABLE_NAME = 'TheTable'))
BEGIN
--Do Stuff
END

【讨论】:

    【解决方案3】:

    使用数据库助手:

    var db = Database.Open("MyDatabase");
    var sql = @"SELECT Count(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'MyTable'"
    var count = db.QueryValue(sql);
    if(count.Equals(1)){
        //table exists
    }
    

    【讨论】:

      【解决方案4】:

      根据 Shiva 的回答,我会这样做:

      if (!File.Exists(sdfPath))
      {
          using (var engine = new SqlCeEngine(dataSource))
          {
              engine.CreateDatabase();
          }
      }
      
      using (var connection = new SqlCeConnection(dataSource))
      {
          connection.Open();
          using (var command = new SqlCeCommand())
          {
              command.Connection = connection;
              command.CommandText ="IF NOT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Platydudes') " 
                                 + "CREATE TABLE Platydudes (Id int NOT NULL, BillSize smallint NOT NULL, Description nvarchar(255) )";
              command.ExecuteNonQuery();
          }
      }
      

      ...根据需要为每个表(Platypups、Platypops 等)重复“使用(var connection = ...”部分)

      更新

      使用 ctacke 的代码,我现在有了这个:

      public static void ConditionallyCreateTables()
      {
          const string sdfPath = @"\Program Files\duckbilled\Platypus.sdf";
          string dataSource = string.Format("Data Source={0}", sdfPath);
      
          if (!File.Exists(sdfPath))
          {
              using (var engine = new SqlCeEngine(dataSource))
              {
                  engine.CreateDatabase();
              }
          }
          using (var connection = new SqlCeConnection(dataSource))
          {
              connection.Open();
              using (var command = new SqlCeCommand())
              {
                  command.Connection = connection;
      
                  if (!TableExists(connection, "InventoryItems"))
                  {
                      command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
                      command.ExecuteNonQuery();
                  }
      
                  if (!TableExists(connection, "Departments"))
                  {
                      command.CommandText = "CREATE TABLE Departments (Id int NOT NULL, DeptNum int NOT NULL, DepartmentName nvarchar(255))";
                      command.ExecuteNonQuery();
                  }
      
                  if (!TableExists(connection, "Subdepartments"))
                  {
                      command.CommandText = "CREATE TABLE Subdepartments (Id int NOT NULL, DeptId int NOT NULL, SubdeptId int NOT NULL, DepartmentName nvarchar(255))";
                      command.ExecuteNonQuery();
                  }
      
                  if (!TableExists(connection, "Redemptions"))
                  {
                      command.CommandText = "CREATE TABLE Redemptions (Id int NOT NULL, RedemptionId nvarchar(50), RedemptionItemId nvarchar(50), RedemptionName nvarchar(255), RedemptionAmount numeric, RedemptionDept nvarchar(50), RedemptionSubdept nvarchar(50))";
                      command.ExecuteNonQuery();
                  }
              }
          }
      }
      

      更新 2

      我现在已将其更改为这种格式:

      if (TableExists(connection, "InventoryItems"))
      {
          command.CommandText = "DROP TABLE InventoryItems";
          command.ExecuteNonQuery();
      }
      command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept float, UnitCost float, UnitList float, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
      command.ExecuteNonQuery();
      

      【讨论】:

        猜你喜欢
        • 2010-09-30
        • 2010-12-02
        • 2010-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多