web-dev-qa-db-fra.com

Vérifier si la base de données existe avant de créer

Cela semble assez trivial, mais cela me frustre maintenant.

J'utilise C # avec SQL Server 2005 Express.

J'utilise le code suivant. Je veux vérifier si une base de données existe avant de la créer. Cependant, le nombre entier renvoyé est -1 et c'est ainsi que MSDN définit ce que ExecuteNonQuery () retournera également. À l'heure actuelle, la base de données existe, mais elle renvoie toujours -1. Cela dit, comment puis-je faire en sorte que le résultat souhaité soit obtenu?

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) { }

}
32
user195488

A partir de SQL Server 2005, les anciennes versions sysobjects et sysdatabases et ces vues de catalogue sont obsolètes. Faites ceci à la place - utilisez le schéma sys. - des vues comme 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;
}

Cela fonctionnera avec n'importe quel nom de base de données que vous transmettez en tant que paramètre et retournera un bool. True = la base de données existe, false = la base de données n'existe pas (ou une erreur s'est produite).

51
marc_s

En lisant cela quelques années plus tard, il existe une manière plus propre de l'exprimer:

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);
           }
      }
}
32
Stephen Lloyd

ça ne devrait pas

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

être ceci?

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

Aussi selon MSDN

Pour les instructions UPDATE, INSERT et DELETE, la valeur renvoyée correspond au nombre de lignes affectées par la commande. Lorsqu'un déclencheur existe sur une table en cours d'insertion ou de mise à jour, la valeur de retour inclut le nombre de lignes affectées par l'opération d'insertion ou de mise à jour et le nombre de lignes affectées par le ou les déclencheurs. Pour tous les autres types d'instructions, la valeur de retour est -1. Si une annulation se produit, la valeur de retour est également -1.

Vous effectuez une instruction SELECT et non une instruction DML. Pourquoi n'utilisez-vous pas une méthode ExecuteReader?

7
SQLMenace

Une alternative à l'interrogation des vues système consiste à utiliser la fonction db_id qui renvoie l'ID de la base de données si elle existe, sinon null. Exemple T-SQL ci-dessous:

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

Vous ne pouvez pas utiliser ExecuteNonQuery car il retournera toujours -1 pour SELECT, comme le montre le lien MSDN.

Vous devrez utiliser un ensemble de résultats, par exemple SELECT DB_ID('INVENTORY') AS DatabaseID ou une variable/paramètre: SELECT @DatabaseID = DB_ID('INVENTORY')

3
gbn

Pour le bénéfice des chercheurs, si vous utilisez Entity Framework, this fonctionnera:

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

Pris le code de Stephen Lloyd et ajouté quelques atténuation asynchrone et injection SQL.

public static async Task<bool> TestDatabase(string connectionString, string databaseName)
{
   using (var connection = new SqlConnection(connectionString))
   using (var command = new SqlCommand("SELECT db_id(@databaseName)", connection))
   {
       command.Parameters.Add(new SqlParameter("databaseName", databaseName));

       connection.Open();

       return (await command.ExecuteScalarAsync() != DBNull.Value);
   }
}
0
Brandon