2010-02-09 19 views
29

Esto parece bastante trivial, pero ahora me está frustrando.Compruebe si existe una base de datos antes de crear

Estoy usando C# con SQL Server 2005 Express.

Estoy usando el siguiente código. Quiero verificar si existe una base de datos antes de crearla. Sin embargo, el número entero devuelto es -1 y así es como MSDN define qué devolverá ExecuteNonQuery(). En este momento, la base de datos existe, pero todavía devuelve -1. Habiendo dicho eso, ¿cómo puedo hacer que esto funcione para obtener el resultado deseado?

private static void checkInventoryDatabaseExists(ref SqlConnection tmpConn, ref bool databaseExists) 
{ 
    string sqlCreateDBQuery; 
    try 
    { 
     tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); 

     sqlCreateDBQuery = "SELECT * FROM master.dbo.sysdatabases where name = 
     \'INVENTORY\'"; 

     using (tmpConn) 
     { 
      tmpConn.Open(); 
      tmpConn.ChangeDatabase("master"); 

      using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn)) 
      { 
       int exists = sqlCmd.ExecuteNonQuery(); 

       if (exists <= 0) 
        databaseExists = false; 
       else 
        databaseExists = true; 
      } 
     } 
    } 
    catch (Exception ex) { } 

} 

Respuesta

43

A partir de SQL Server 2005, el viejo estilo sysobjects y sysdatabases y esas vistas de catálogo han quedado en desuso. Para ello, en lugar - utilizar el esquema sys. - vistas como sys.databases

private static bool CheckDatabaseExists(SqlConnection tmpConn, string databaseName) 
{ 
    string sqlCreateDBQuery; 
    bool result = false; 

    try 
    { 
     tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); 

     sqlCreateDBQuery = string.Format("SELECT database_id FROM sys.databases WHERE Name 
     = '{0}'", databaseName); 

     using (tmpConn) 
     { 
      using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn)) 
      { 
       tmpConn.Open(); 

       object resultObj = sqlCmd.ExecuteScalar(); 

       int databaseID = 0;  

       if (resultObj != null) 
       { 
        int.TryParse(resultObj.ToString(), out databaseID); 
       } 

       tmpConn.Close(); 

       result = (databaseID > 0); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     result = false; 
    } 

    return result; 
} 

Esto funciona con cualquier nombre de base de datos se pasa como un parámetro, y se volverán existe, no existe un bool true = base de datos falsos = base de datos (o error ocurrido).

+1

intentándolo ahora ... executescalar devuelve el objeto, por lo que debe realizar el reparto antes de la asignación. –

+0

Arroja una excepción de "Nombre de columna inválido 'INVENTARIO'" –

+1

lo siento, sí - el nombre de la base de datos debe estar entre comillas simples - actualicé mi respuesta –

6

no debería esta

"SELECT * FROM master.dbo.sysdatabases where name = \'INVENTORY\'" 

ser esto?

"SELECT * FROM master.dbo.sysdatabases where name = 'INVENTORY'" 

También de acuerdo con MSDN

For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.

que está haciendo una instrucción DML no un SELECT. ¿Por qué no utilizas un método ExecuteReader en su lugar?

+0

ningún efecto sobre el resultado .. sigue devolviendo -1 –

+0

me gustaría utilizar ExecuteReader lugar ya que no se está haciendo de todos modos LMD – SQLMenace

+0

esto debería sea ​​un comentario, pero buen punto –

2

No puede usar ExecuteNonQuery porque siempre devolverá -1 para SELECT, como muestra el enlace de MSDN.

Vas a tener que utilizar un proceso de ejemplo de resultados SELECT DB_ID('INVENTORY') AS DatabaseID o utilizar una variable/parámetro: SELECT @DatabaseID = DB_ID('INVENTORY')

2

Una alternativa para consultar las vistas del sistema es usar la función db_id que devuelve el Id de la base de datos si existe, de lo contrario nulo. Ejemplo de T-SQL a continuación:

if (db_id('INVENTORY') is null) 
begin 
    return 0 
end 
else 
begin 
    return 1 
end 
28

La lectura de este algunos años en y no hay una forma más limpia de expresar esto:

public static bool CheckDatabaseExists(string connectionString, string databaseName) 
{ 
     using (var connection = new SqlConnection(connectionString)) 
     { 
      using (var command = new SqlCommand($"SELECT db_id('{databaseName}')", connection)) 
      { 
       connection.Open(); 
       return (command.ExecuteScalar() != DBNull.Value); 
      } 
     } 
} 
+0

tenga cuidado con la inyección de SQL aquí, use consultas parametrizadas en lugar de interpolación de cadenas – AndrewK

0

Para el beneficio de los buscadores, si está utilizando Entity Framework, this se trabajo:

using (var ctx = new MyDataModel()) 
{ 
    dbExists = System.Data.Entity.Database.Exists(ctx.Database.Connection); 
} 
Cuestiones relacionadas