web-dev-qa-db-ja.com

SQLテーブルが存在するかどうかを確認します

データベースに依存しない方法でSqlデータベースにテーブルが存在するかどうかを確認する最良の方法は何ですか?

私は思いついた:

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

これを行うためのより良い方法はありますか?このメソッドは、データベースへの接続が失敗すると機能しません。 Sybase、SQLサーバー、Oracleの方法を見つけましたが、すべてのデータベースで機能するものはありません。

39
Carra
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;
    }
}
64
Michael Buen

これは、DBの構築方法に依存する非常に特殊なものであるため、すべてのデータベースで機能する1つの一般的な方法が存在するとは思わない。

しかし、なぜ特定のクエリを使用してこれを行うのですか?あなたがしたいことから実装を抽象化することはできませんか?つまり、たとえば 'TableExists(string tablename)'というメソッドを含む汎用インターフェイスを作成しないのはなぜですか。次に、サポートする各DBMSに対して、このインターフェイスを実装するクラスを作成し、TableExistsメソッドで、このDBMSに特定のロジックを記述します。
SQLServer実装には、sysobjectsをクエリするクエリが含まれます。

アプリケーションでは、特定のコンテキストの正しい実装を作成するファクトリクラスを作成し、TableExistsメソッドを呼び出すだけです。

例えば:

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

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

これが私がやるべき方法だと思います。

10

データベースの独立性を目指している場合は、最小限の標準を想定する必要があります。 IIRC ANSI INFORMATION_SCHEMA ビューはODBCに準拠するために必要であるため、次のようにクエリできます。

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

ODBCを使用している場合、さまざまな ODBC API呼び出し を使用して、このメタデータも取得できます。

移植性は write-once testどこでも と等しいため、サポートする予定のすべてのプラットフォームでアプリケーションをテストする必要があることに注意してください。つまり、テスト用のリソースは非常に限られているため、データベースプラットフォームの数は限られています。

その結果、アプリケーションの最小公分母(SQLを探すよりもかなり難しい)を見つけるか、プラットフォームごとに移植不可能な関数をプラグインできるプラットフォーム依存セクションを構築する必要があります基礎。

select count(x) from xxxxxxの実行は避けたいと思います。DBMSが実際に実行し、それを実行するため、大きなテーブルでは時間がかかる可能性があるためです。

代わりに 準備する select * from mysterytableクエリ。 mysterytableが存在しない場合、準備は失敗します。準備されたステートメントを実際に実行する必要はありません。

4
James Anderson

Frederik Gheyselsの回答を完全にサポートします。複数のデータベースシステムをサポートする必要がある場合は、データベースシステムごとに特定の実装を持つ抽象インターフェイスに対してコードを実装する必要があります。互換性のない構文の例は、既存のテーブルをチェックするだけではありません(例:クエリを特定の行数に制限する)。

ただし、例の例外処理を使用して実際にチェックを実行する必要がある場合は、データベースに実際の選択作業がないため、COUNT(*)よりも効率的な次のクエリを使用する必要があります。

SELECT 1 FROM my_table WHERE 1=2
4
Sebastian Dietz

次は私のためにうまくいきます...

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; }
}
2
Arvo Bowen

私の仕事の現在のプロジェクトでは、多くのデータベースタイプをサポートする「データエージェント」を作成する必要があります。

だから私は次のことをすることにしました:仮想メソッドを使用してベース(データベースに依存しない)機能を持つベースクラスを作成し、サブクラスですべてのデータベース固有の瞬間をオーバーライドします

2
abatishchev

Try-catchソリューションを避けたい場合は、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

とてもシンプル

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

答えが1の場合、テーブルがあります。答えが0の場合、テーブルはありません。

0