检查SQL表是否存在

时间:2009-01-21 08:48:25

标签: c# .net sql ado.net odbc

以数据库独立的方式检查Sql数据库中是否存在表的最佳方法是什么?

我想出了:

   bool exists;
   const string sqlStatement = @"SELECT COUNT(*) FROM my_table";

   try
    {
       using (OdbcCommand cmd = new OdbcCommand(sqlStatement, myOdbcConnection))
       {
            cmd.ExecuteScalar();
            exists = true;
       }
    }
    catch
    {
        exists = false;
    }

有更好的方法吗?当与数据库的连接失败时,此方法将不起作用。我已经找到了Sybase,SQL服务器,Oracle的方法,但没有任何适用于所有数据库的方法。

9 个答案:

答案 0 :(得分:63)

bool exists;

try
{
    // ANSI SQL way.  Works in PostgreSQL, MSSQL, MySQL.  
    var cmd = new OdbcCommand(
      "select case when exists((select * from information_schema.tables where table_name = '" + tableName + "')) then 1 else 0 end");

    exists = (int)cmd.ExecuteScalar() == 1;
}
catch
{
    try
    {
        // Other RDBMS.  Graceful degradation
        exists = true;
        var cmdOthers = new OdbcCommand("select 1 from " + tableName + " where 1 = 0");
        cmdOthers.ExecuteNonQuery();
    }
    catch
    {
        exists = false;
    }
}

答案 1 :(得分:10)

我不认为存在一种适用于所有数据库的通用方法,因为这是非常具体的,取决于数据库的构建方式。

但是,为什么要使用特定查询来执行此操作? 难道你不能将实现抽象出你想做的事情吗? 我的意思是:为什么不创建一个通用接口,其中包括一个名为'TableExists(string tablename)'的方法。 然后,对于您要支持的每个DBMS,您将创建一个实现此接口的类,并在TableExists方法中为此DBMS编写特定逻辑。
然后,SQLServer实现将包含一个查询sysobjects的查询。

在您的应用程序中,您可以拥有一个工厂类,为给定的上下文创建正确的实现,然后您只需调用TableExists方法。

例如:

IMyInterface foo = MyFactory.CreateMyInterface (SupportedDbms.SqlServer);

if( foo.TableExists ("mytable") )
...

我认为我应该这样做。

答案 2 :(得分:9)

如果您正在尝试数据库独立性,则必须采用最低标准。 IIRC ODBC {1}视图是ODBC一致性所必需的,因此您可以查询它们,如:

select count (*) 
  from information_schema.tables 
 where table_name = 'foobar'

鉴于您使用的是ODBC,您还可以使用各种INFORMATION_SCHEMA来检索此元数据。

请记住,可移植性等同于ODBC API calls,因此您仍然需要在您打算支持的每个平台上测试应用程序。这意味着您本身仅限于有限数量的可能数据库平台,因为您只有大量的测试资源。

结果是你需要为你的应用程序找到一个最小的公分母(这比查找SQL要困难得多)或者构建一个平台相关的部分,其中非便携式函数可以插入到每个平台的基础。

答案 3 :(得分:4)

我完全支持Frederik Gheysels的回答。如果必须支持多个数据库系统,则应针对每个数据库系统具有特定实现的抽象接口实现代码。除了检查现有表之外,还有更多不兼容语法的示例(例如:将查询限制为特定行数)。

但是如果你真的必须使用你的例子中的异常处理来执行检查,你应该使用比COUNT(*)更高效的以下查询,因为数据库没有实际的选择工作:

SELECT 1 FROM my_table WHERE 1=2

答案 4 :(得分:4)

我会避免执行select count(x) from xxxxxx,因为DBMS实际上会继续执行它,这可能需要一些时间来处理大型表。

而只是准备 select * from mysterytable查询。如果不存在神秘感,准备将失败。没有必要实际执行准备好的语句。

答案 5 :(得分:2)

在我工作的当前项目中,我需要编写支持大量数据库类型的“数据代理”。

所以我决定做下一步:使用虚拟方法编写一个基类(独立于数据库)功能的基类,并在子类中覆盖所有特定于数据库的时刻

答案 6 :(得分:2)

以下适用于我......

private bool TableExists(SqlConnection conn, string database, string name)
{
    string strCmd = null;
    SqlCommand sqlCmd = null;

    try
    {
        strCmd = "select case when exists((select '['+SCHEMA_NAME(schema_id)+'].['+name+']' As name FROM [" + database + "].sys.tables WHERE name = '" + name + "')) then 1 else 0 end";
        sqlCmd = new SqlCommand(strCmd, conn);

        return (int)sqlCmd.ExecuteScalar() == 1;
    }
    catch { return false; }
}

答案 7 :(得分:0)

如果你想避免try-catch解决方案,我建议使用sys.tables

这个方法
private bool IsTableExisting(string table)
    {
        string command = $"select * from sys.tables";
        using (SqlConnection con = new SqlConnection(Constr))
        using (SqlCommand com = new SqlCommand(command, con))
        {
            SqlDataReader reader = com.ExecuteReader();
            while (reader.Read())
            {
                if (reader.GetString(0).ToLower() == table.ToLower())
                    return true;
            }
            reader.Close();
        }
        return false;
    }

答案 8 :(得分:0)

非常简单

use YOUR_DATABASE --OPTIONAL
SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name = 'YOUR_TABLE_NAME'

如果答案是1,则有一张表。 如果答案是0,则没有表格。