2009-01-21 146 views
37

检查数据库独立方式下Sql数据库中是否存在表的最佳方法是什么?检查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 Server,Oracle的方法,但没有适用于所有数据库的方法。

+1

更好的方法是使用“SELECT 1 FROM`tbl` WHERE 1 = 0”这样它就不会像资源消耗一样。 – 2009-01-21 09:01:02

回答

56
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; 
    } 
} 
+0

有关Sql-Server中information_schema的更多信息,请参阅此链接http://msdn.microsoft.com/en-us/library/ms186778.aspx。 – GvS 2009-01-21 10:25:42

+1

-1 from me。这在MySql中不起作用。如果任何数据库有一个名为'tableName'的表,它将返回true。我用MySql5.1 + Navicat8测试了这个。 – anonymous 2010-04-30 17:41:35

10

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

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

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

例如:

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

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

我觉得这是我应该怎么做。

+1

这就是我们在主应用程序中执行此操作的方式。 但是,如果你只是有一个odbc连接,并不知道它背后是什么数据库呢? – Carra 2009-01-21 09:17:15

+0

我的经验告诉我这是一种错误的方式!您可能会得到零性能,不幸的是 – abatishchev 2009-01-21 09:29:22

+0

@abtischev - 请您详细介绍一下吗? – MPritchard 2010-06-11 06:59:22

4

我完全支持弗雷德里克Gheysels的答案。如果您必须支持多个数据库系统,则应该针对每个数据库系统的特定实现的抽象接口实现您的代码。与仅检查现有表格相比,还有更多不兼容的语法示例(例如:将查询限制为一定数量的行)。

但是,如果您确实需要使用示例中的异常处理执行检查,则应该使用比COUNT(*)更高效的以下查询,因为数据库没有实际的选择工作要做:

SELECT 1 FROM my_table WHERE 1=2 
2

在我工作的当前项目中,我需要编写'数据代理',它可以支持很多数据库类型。

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

4

我会避免执行select count(x) from xxxxxx作为DBMS实际上会继续做吧,这可能需要一些时间才能放大桌子。

取而代之的只是准备 a select * from mysterytable查询。如果mysterytable不存在,准备将失败。没有必要实际执行准备好的声明。

9

如果您尝试数据库独立性,您将不得不承担最低标准。IIRC的ANSI INFORMATION_SCHEMA意见所必需的ODBC一致性,这样你就可以查询对他们的喜欢:

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

假设你正在使用ODBC,你还可以使用各种ODBC API calls检索元数据也是如此。

请记住,可移植性等同于write-once test anywhere,因此您仍然必须在您打算支持的每个平台上测试应用程序。这意味着,您固有地仅限于有限数量的可能的数据库平台,因为您只有很多测试资源。

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

1

下很适合我......

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

如果你想避免的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; 
    } 
0

非常简单

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

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