Controlla se esiste una tabella SQL

Qual è il modo migliore per verificare se esiste una tabella in un database Sql in un modo indipendente dal database?

Mi sono inventato:

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

C’è un modo migliore per farlo? Questo metodo non funzionerà quando la connessione al database fallisce. Ho trovato modi per Sybase, SQL server, Oracle ma nulla che funzioni per tutti i database.

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

Non penso che esista un modo generico che funzioni per tutti i database, poiché questo è qualcosa di molto specifico che dipende da come viene costruito il DB.

Ma, perché vuoi farlo usando una query specifica? Non puoi astrarre l’implementazione da ciò che vuoi fare? Voglio dire: perché non creare un’interfaccia generica, che ha, tra l’altro, un metodo chiamato ‘TableExists (string tablename)’ per esempio. Quindi, per ogni DBMS che si desidera supportare, si crea una class che implementa questa interfaccia e, nel metodo TableExists, si scrive una logica specifica per questo DBMS.
L’implementazione SQLServer conterrà quindi una query che interroga sysobjects.

Nell’applicazione, è ansible avere una class factory che crea l’implementazione corretta per un determinato contesto e quindi basta chiamare il metodo TableExists.

Per esempio:

 IMyInterface foo = MyFactory.CreateMyInterface (SupportedDbms.SqlServer); if( foo.TableExists ("mytable") ) ... 

Penso che sia così che dovrei farlo.

Se stai cercando l’indipendenza del database, dovrai assumere uno standard minimo. IIRC Le visualizzazioni ANSI INFORMATION_SCHEMA sono richieste per la conformità ODBC, pertanto è ansible eseguire query su di esse come:

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

Dato che stai utilizzando ODBC, puoi anche utilizzare varie chiamate API ODBC per recuperare anche questi metadati.

Tieni a mente che la portabilità equivale a scrivere una volta il test ovunque, quindi dovrai comunque testare l’applicazione su ogni piattaforma che intendi supportare. Ciò significa che si è intrinsecamente limitati a un numero finito di possibili piattaforms di database poiché si ha così tanta risorsa da testare.

Il risultato è che devi trovare un minimo comune denominatore per la tua applicazione (che è molto più difficile di quanto sembri per SQL) o build una sezione dipendente dalla piattaforma in cui le funzioni non portatili possono essere inserite su una piattaforma base.

Sostengo pienamente la risposta di Frederik Gheysels. Se è necessario supportare più sistemi di database, è necessario implementare il codice su un’interfaccia astratta con implementazioni specifiche per sistema di database. Esistono molti altri esempi di syntax incompatibile rispetto al solo controllo di una tabella esistente (ad esempio limitando la query a un certo numero di righe).

Ma se davvero devi eseguire il controllo usando la gestione delle eccezioni dal tuo esempio, dovresti utilizzare la seguente query che è più efficiente di un COUNT (*) perché il database non ha lavoro di selezione effettivo da eseguire:

 SELECT 1 FROM my_table WHERE 1=2 

Eviterei di eseguire il select count(x) from xxxxxx poiché il DBMS andrà effettivamente avanti e lo farà, cosa che potrebbe richiedere del tempo per una tabella di grandi dimensioni.

Invece basta preparare una select * from mysterytable query select * from mysterytable . La preparazione fallirà se mysterytable non esiste. Non è necessario eseguire effettivamente la dichiarazione preparata.

Nell’attuale progetto sul mio lavoro ho bisogno di scrivere “agente dati” che supporti molti tipi di database.

Così ho deciso di fare il prossimo: scrivere una class base con la funzionalità base (indipendente dal database) usando metodi virtuali e sovrascrivere in sottoclassi tutti i momentjs specifici del database

Quanto segue funziona bene per me …

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

Se vuoi evitare soluzioni try-catch, sto suggerendo questo metodo, 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; } 

Molto semplice

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

Se la risposta è 1, c’è un tavolo. Se la risposta è 0, non c’è tabella.