2009-01-21 33 views
37

¿Cuál es la mejor manera de verificar si una tabla existe en una base de datos Sql en una base de datos de manera independiente?Compruebe si existe una tabla SQL

me ocurrió:

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

¿Hay una mejor manera de hacer esto? Este método no funcionará cuando la conexión a la base de datos falla. He encontrado formas para Sybase, SQL server, Oracle pero nada que funcione para todas las bases de datos.

+1

Una forma mejor sería usar "SELECT 1 FROM' tbl' DONDE 1 = 0 "De esta forma no consumirá tantos recursos. –

Respuesta

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

Consulte este enlace http://msdn.microsoft.com/en-us/library/ms186778.aspx para obtener más información sobre information_schema en Sql-Server. – GvS

+1

-1 de mí. Esto no funciona en MySql. Coz, devuelve verdadero si cualquier base de datos tiene una tabla llamada 'tableName'. He probado esto con MySql5.1 + Navicat8. – anonymous

+0

@JMSA: lo siento, olvidé incluir el nombre_esquema (el campo de nombre de la base de datos). 'select * from information_schema.tables donde schema_name = 'yourDatabaseNameHere' y table_name = 'yourTableNameHere'. amablemente deshacer el voto a la baja –

10

No creo que exista una forma genérica que funcione para todas las bases de datos, ya que esto es algo muy específico que depende de cómo se construya la base de datos.

Pero, ¿por qué quieres hacer esto con una consulta específica? ¿No puede abstraer la implementación de lo que desea hacer? Quiero decir: ¿por qué no crear una interfaz genérica, que tiene, entre otros, un método llamado 'TableExists (string tablename)' por ejemplo. Luego, para cada DBMS que quiera admitir, crea una clase que implementa esta interfaz, y en el método TableExists, escribe una lógica específica para este DBMS.
La implementación de SQLServer contendrá una consulta que consulta sysobjects.

En su aplicación, puede tener una clase de fábrica que crea la implementación correcta para un contexto dado, y luego simplemente llama al método TableExists.

Por ejemplo:

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

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

Creo que esta es la forma en que debería hacerlo.

+1

Así es como lo hacemos en nuestra aplicación principal. Sin embargo, ¿qué sucede si solo tiene una conexión odbc y no sabe qué base de datos hay detrás? – Carra

+0

¡Mi experiencia dice que esto es una manera incorrecta! Posiblemente obtendría un rendimiento nulo, lamentablemente – abatishchev

+0

@abtischev, ¿podría entrar en más detalles, por favor? – MPritchard

4

Apoyo totalmente a Frederik Gheysels answer. Si tiene que admitir múltiples sistemas de bases de datos, debe implementar su código contra una interfaz abstracta con implementaciones específicas por sistema de base de datos. Hay muchos más ejemplos de sintaxis incompatible que simplemente verificar una tabla existente (por ejemplo, limitar la consulta a un cierto número de filas).

Pero si realmente tiene que realizar el control con el manejo de su ejemplo excepción, debe utilizar la siguiente consulta que es más eficiente que un COUNT (*) debido a que la base de datos tiene ninguna obra selección real de hacer:

SELECT 1 FROM my_table WHERE 1=2 
2

En el proyecto actual en mi trabajo, necesito escribir 'data agent', que admitiría una gran cantidad de tipos de bases de datos.

así que decidí hacer a continuación: escribir una clase base con la base de la funcionalidad (base de datos independiente) utilizando métodos virtuales y anular en las subclases todos los momentos bases de datos específicas

+0

Definitivamente la manera de hacer esto, sí. – Nyerguds

4

evitaría la ejecución de la select count(x) from xxxxxx como el DBMS en realidad se seguir adelante y hacerlo, lo que puede tomar un tiempo para una gran mesa.

En su lugar solo prepare a select * from mysterytable consulta. La preparación fallará si no existe una tabla misteriosa. No es necesario ejecutar realmente la declaración preparada.

+0

No sé sobre ODBC, pero en Oracle utilizando JDBC puede preparar una declaración que fallará totalmente cuando la ejecute. –

+0

Sí, pero él solo quiere enviar un mensaje si existe la tabla que preparará validar.Especialmente si es el simple "Seleccione * de ?????" que solo puede fallar si ??? no existe. –

+0

Realmente dudo que "select count (*)" (con ninguna cláusula where) lleve mucho tiempo para una tabla grande; me imagino que todas las bases de datos almacenan recuentos de filas en bases de datos internas/índices/cachés, por lo que sería solo un búsqueda simple. El tamaño de la tabla, por lo tanto, no tendría ninguna relación con el tiempo que tarda la consulta en ejecutarse. –

9

Si intenta independizar la base de datos, deberá asumir un estándar mínimo.Se requieren IIRC El ANSI INFORMATION_SCHEMA vistas para ODBC conformidad, por lo que podrían consultar en contra de ellos les gusta:

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

Dado que está utilizando ODBC, también puede utilizar varios ODBC API calls para recuperar estos metadatos también.

Tenga en cuenta que la portabilidad equivale a write-once test anywhere, por lo que todavía tendrá que probar la aplicación en cada plataforma que pretenda admitir. Esto significa que está intrínsecamente limitado a un número finito de plataformas de bases de datos posibles ya que solo tiene tantos recursos para probar.

El resultado es que necesita encontrar un mínimo común denominador para su aplicación (que es bastante más difícil de lo que parece para SQL) o crear una sección dependiente de la plataforma donde las funciones no portátiles se pueden conectar en una por plataforma.

+0

Entonces, si entiendo tu publicación correctamente, ¿cada DBMS debería tener una vista INFORMATION_SCHEMA según algún estándar? –

+0

Creo que las vistas INFORMATION_SCHEMA son necesarias para cumplir con la norma ANSI SQL-92. Sin embargo, los proveedores de DBMS tienden a jugar un poco rápido y con los estándares ANSI SQL en sus afirmaciones de cumplimiento. – ConcernedOfTunbridgeWells

1

Los siguientes trabajos bien para mí ...

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

Si se quiere evitar soluciones try-catch, estoy sugiriendo este método, usando 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

muy simple

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

Si la respuesta es 1, hay una tabla. Si la respuesta es 0, no hay tabla.