检查一个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; }
有一个更好的方法吗? 与数据库的连接失败时,此方法不起作用。 我已经find了Sybase,SQL服务器,Oracle的方法,但没有适用于所有数据库。
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; } }
我不认为存在一种适用于所有数据库的通用方法,因为这是非常具体的,取决于如何构build数据库。
但是,为什么要使用特定查询来执行此操作? 难道你不能从你想做的事情中抽象出实现吗? 我的意思是:为什么不创build一个通用接口,其中包括一个名为“TableExists(string tablename)”的方法。 然后,对于您要支持的每个DBMS,创build一个实现此接口的类,并在TableExists方法中为此DBMS编写特定的逻辑。
SQLServer实现将包含一个查询sysobjects的查询。
在你的应用程序中,你可以有一个工厂类为给定的上下文创build正确的实现,然后调用TableExists方法。
例如:
IMyInterface foo = MyFactory.CreateMyInterface (SupportedDbms.SqlServer); if( foo.TableExists ("mytable") ) ...
我认为这是我应该做的。
如果您尝试数据库独立性,则必须采用最低标准。 IIRC ANSI INFORMATION_SCHEMA视图是ODBC一致性所必需的,因此您可以像这样查询它们:
select count (*) from information_schema.tables where table_name = 'foobar'
考虑到您正在使用ODBC,您还可以使用各种ODBC API调用来检索此元数据。
请记住,可移植性相当于在任何地方进行一次写入testing,所以您仍然需要在每个您打算支持的平台上testing应用程序。 这意味着,由于您只有很多testing资源,所以您本质上只限于有限数量的数据库平台。
结果是,您需要为您的应用程序find一个最小公分母(这比查找SQL要困难得多),或者构build一个平台相关的部分,其中非可移植函数可以插入到每个平台基础。
我完全支持弗雷德里克·希泽尔斯的回答。 如果您必须支持多个数据库系统,则应该针对每个数据库系统的特定实现抽象接口来实现您的代码。 还有更多的不兼容的语法的例子,只是检查一个现有的表(例如:限制查询一定数量的行)。
但是,如果您确实需要使用示例中的exception处理来执行检查,那么应该使用比COUNT(*)更高效的以下查询,因为数据库没有实际的select工作要做:
SELECT 1 FROM my_table WHERE 1=2
我会避免select count(x) from xxxxxx
执行select count(x) from xxxxxx
因为DBMS将会实际执行,而这可能需要一些时间来处理大表。
而只是准备一个select * from mysterytable
查询。 如果mysterytable不存在,准备将失败。 没有必要真正执行准备好的声明。
在当前的工作中,我需要编写“数据代理”来支持很多数据库types。
所以我决定做下一步:使用虚拟方法编写一个基类(数据库独立)function的基类,并在子类中覆盖所有特定于数据库的时刻
以下的作品适合我…
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; } }
如果你想避免try-catch解决scheme,我使用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; }