47 votes

Vérifier si une table SQL existe

Quelle est la meilleure façon de vérifier si une table existe dans une base de données Sql d'une manière indépendante de la base de données ?

Je suis venu avec :

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

Existe-t-il une meilleure façon de procéder ? Cette méthode ne fonctionne pas lorsque la connexion à la base de données échoue. J'ai trouvé des méthodes pour Sybase, SQL server, Oracle mais rien qui fonctionne pour toutes les bases de données.

3 votes

Une meilleure solution serait d'utiliser "SELECT 1 FROM tbl WHERE 1=0" De cette façon, il ne sera pas aussi consommateur de ressources.

69voto

Michael Buen Points 20453
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 votes

Voir ce lien msdn.microsoft.com/fr/us/library/ms186778.aspx pour plus d'informations sur l'information_schema dans Sql-Server.

1 votes

-1 de moi. Cela ne fonctionne pas avec MySql. Parce qu'il renvoie vrai si une base de données a une table nommée 'tableName'. J'ai testé ceci avec MySql5.1 + Navicat8.

0 votes

@JMSA : désolé, j'ai oublié d'inclure le schema_name (le champ du nom de la base de données). select * from information_schema.tables where schema_name = 'yourDatabaseNameHere' and table_name = 'yourTableNameHere . veuillez annuler le downvote

13voto

Si vous essayez d'obtenir l'indépendance de la base de données, vous devrez assumer une norme minimale. IIRC L'ANSI INFORMATION_SCHEMA sont nécessaires pour la conformité à l'ODBC. Vous pouvez donc effectuer des requêtes sur ces vues de la manière suivante :

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

Étant donné que vous utilisez ODBC, vous pouvez également utiliser diverses Appels ODBC API pour récupérer également ces métadonnées.

Gardez à l'esprit que la portabilité équivaut à test write-once n'importe où Vous devrez donc toujours tester l'application sur chaque plate-forme que vous avez l'intention de prendre en charge. Cela signifie que vous êtes intrinsèquement limité à un nombre fini de plates-formes de base de données possibles, car vous ne disposez que d'un nombre limité de ressources pour les tests.

Le résultat est que vous devez trouver un plus petit dénominateur commun pour votre application (ce qui est beaucoup plus difficile qu'il n'y paraît pour SQL) ou construire une section dépendante de la plate-forme où les fonctions non portables peuvent être ajoutées sur une base par plate-forme.

1 votes

Alors, si je comprends bien votre message, chaque SGBD devrait avoir une vue INFORMATION_SCHEMA selon un certain standard ?

0 votes

Je pense que les vues INFORMATION_SCHEMA sont nécessaires pour la conformité à la norme ANSI SQL-92. Cependant, les fournisseurs de SGBD ont tendance à jouer un peu vite et lâchement avec les normes ANSI SQL dans leurs déclarations de conformité.

10voto

Frederik Gheysels Points 36354

Je ne pense pas qu'il existe une méthode générique qui fonctionne pour toutes les bases de données, car il s'agit de quelque chose de très spécifique qui dépend de la façon dont la base de données est construite.

Mais, pourquoi voulez-vous faire cela en utilisant une requête spécifique ? Ne pouvez-vous pas abstraire l'implémentation de ce que vous voulez faire ? Je veux dire : pourquoi ne pas créer une interface générique, qui a, entre autres, une méthode appelée 'TableExists( string tablename )' par exemple. Ensuite, pour chaque SGBD que vous voulez supporter, vous créez une classe qui implémente cette interface, et dans la méthode TableExists, vous écrivez une logique spécifique pour ce SGBD.
L'implémentation de SQLServer contiendra alors une requête qui interroge les sysobjects.

Dans votre application, vous pouvez avoir une classe d'usine qui crée l'implémentation correcte pour un contexte donné, et ensuite vous appelez simplement la méthode TableExists.

Par exemple :

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

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

Je pense que c'est comme ça que je dois faire.

1 votes

C'est ainsi que nous procédons dans notre application principale. Cependant, que se passe-t-il si vous avez simplement une connexion odbc et que vous ne savez pas quelle base de données se cache derrière ?

0 votes

D'après mon expérience, c'est une mauvaise méthode ! Vous obtiendrez probablement des performances nulles, malheureusement

0 votes

@abtischev - Pourriez-vous nous donner plus de détails ?

5voto

Sebastian Dietz Points 4309

Je soutiens pleinement la réponse de Frederik Gheysels. Si vous devez prendre en charge plusieurs systèmes de base de données, vous devez implémenter votre code par rapport à une interface abstraite avec des implémentations spécifiques par système de base de données. Il existe bien d'autres exemples de syntaxe incompatible que la simple vérification de l'existence d'une table (par exemple : limiter la requête à un certain nombre de lignes).

Mais si vous devez vraiment effectuer la vérification en utilisant le traitement des exceptions de votre exemple, vous devez utiliser la requête suivante qui est plus efficace qu'un COUNT(*) car la base de données n'a pas de travail de sélection à effectuer :

SELECT 1 FROM my_table WHERE 1=2

4voto

James Anderson Points 18253

J'éviterais d'exécuter le select count(x) from xxxxxx car le SGBD le fera, ce qui peut prendre un certain temps pour une grande table.

Au lieu de cela, il suffit de préparer a select * from mysterytable la requête. La préparation échouera si mysterytable n'existe pas. Il n'est pas nécessaire d'exécuter réellement l'instruction préparée.

0 votes

Je ne sais pas ce qu'il en est d'ODBC, mais sur Oracle, en utilisant JDBC, vous pouvez préparer une instruction qui échouera totalement lorsque vous l'exécuterez.

0 votes

Oui mais il veut seulement vérifier si la table existe, ce que prepare validera. Surtout s'il s'agit d'un simple "Select * from ? ????" qui ne peut échouer que si ? ?? n'existe pas.

0 votes

Je doute vraiment que "select count(*)" (sans clause where) prenne beaucoup de temps pour une grande table - j'imagine que toutes les bases de données stockent les rowcounts dans des bases de données/index/caches internes, et qu'il ne s'agit donc que d'une seule consultation. La taille de la table n'a donc aucune incidence sur le temps d'exécution de la requête.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X