SQLiteでテーブルが存在するかどうかを確認するにはどうすればよいですか?


894

特定のユーザーテーブルが存在するかどうかを確実にSQLiteで確認するにはどうすればよいですか?

テーブルの "select *"がエラーを返したかどうかをチェックするような信頼できない方法を求めているのではありません(これは良いアイデアですか?)。

その理由は次のとおりです。

私のプログラムでは、いくつかのテーブルがまだ存在しない場合は、作成してデータを設定する必要があります。

それらがすでに存在する場合、いくつかのテーブルを更新する必要があります。

問題のテーブルがすでに作成されていることを通知するために、代わりに他のパスを使用する必要があります-たとえば、ディスク上のプログラムの初期化/設定ファイルで特定のフラグを作成/出力/設定することによって、

それとも私のアプローチは理にかなっていますか?


selectのテーブルが存在しない場合、SQLiteは例外をスローします。もう手間のかかる作業は必要ありません。
NoChance

34
@NoChanceはそうしますが、他の数も同様です。これは、目を閉じて前進することで、そのツリーが本当に存在するかどうかを確認するのと少し似ています。どちらかを見つけることができます:)
randomsock

車は私の車だった特別な場合@randomsock、良い例が、少し怖い、...
NoChance

@randomsock、私はsqlite規約とは何なのかわかりませんが、許可よりも許しを求める方がpythonicです。つまり、条件を使用する代わりに例外をキャッチします。
エリック

1
@Eric現在のところ、質問にはPythonは含まれていませんが、Pythonが含まれていると仮定すると、エラーは一般的なものsqlite3.OperationalErrorであるため、作成時に「テーブルTABLE_NAMEがすでに存在する」などのエラーメッセージであることを確認するために、エラーメッセージを解析する必要があります。テーブルを作成し、そうでない場合はエラーを再発生させます。エラーの表現が変更されないという保証はありません。
Markus von Broady

回答:


1022

そのFAQエントリを逃しました。

とにかく、将来の参考のために、完全なクエリは次のとおりです。

SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';

{table_name}チェックするテーブルの名前はどこですか。

参照用のドキュメントセクション:データベースファイル形式。2.6。SQLデータベーススキーマのストレージ

  • これは、指定された名前のテーブルのリストを返します。つまり、カーソルのカウントは0(存在しない)または1(存在する)になります。

7
これらのシステムテーブルについて説明しているSQLiteのドキュメントはどれですか。
Pawel Veselov、2012年

29
@Pawel Veselov:「SQLiteデータベースのファイル形式」というタイトルのセクション:sqlite.org/fileformat2.html
Bryan Oakley

14
ただし、これはTEMPテーブルでは機能しません。TEMPテーブルは「sqlite_temp_master」にあります。
PatchyFog

11
これはブール値を返しますか?テーブルが存在する場合、または存在しない場合、何を返しますか?
ダグルームズ2015年

8
@Dagroomsこれは、指定された名前のテーブルのリストを返します。つまり、カーソルのカウントは0(存在しない)または1(存在する)になります。
Rein S

555

SQLiteバージョン3.3以降を使用している場合は、次のコマンドでテーブルを簡単に作成できます。

create table if not exists TableName (col1 typ1, ..., colN typN)

同様に、次のコマンドを使用して、存在する場合にのみテーブルを削除できます。

drop table if exists TableName

3
create tableステートメントが不完全であることに注意してください(テーブル列の指定がありません)。
エリックプラトン2013年

11
インデックスにも同様の構成があります。存在しない場合はインデックスを作成
lowtech

26
これは受け入れられる答えではありませんが、質問の言い方が異なる場合はそうなります。OPは、ドロップまたは作成する前にテーブルをチェックする方法を尋ねませんでした。存在しない可能性のあるテーブルをクエリする必要がある場合はどうなりますか?これが私が今直面している問題であり、受け入れられた答えはこの一般的な問題の説明で最もよく機能します。これは優れた迅速な代替手段です。
ダグルームズ2015年

@Dagrooms、あなたは正しいかもしれません。OPはこれを要求しませんでしたが、私はこの答えを探していました:)
earik87

169

バリエーションは、SELECT NAMEの代わりにSELECT COUNT(*)を使用することです。

SELECT count(*) FROM sqlite_master WHERE type='table' AND name='table_name';

テーブルが存在しない場合は0を返し、存在する場合は1を返します。数値結果の方が処理が速く/簡単であるため、これはおそらくプログラミングに役立ちます。以下は、SQLiteDatabase、Cursor、rawQueryをパラメーターと共に使用してAndroidでこれを行う方法を示しています。

boolean tableExists(SQLiteDatabase db, String tableName)
{
    if (tableName == null || db == null || !db.isOpen())
    {
        return false;
    }
    Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type = ? AND name = ?", new String[] {"table", tableName});
    if (!cursor.moveToFirst())
    {
        cursor.close();
        return false;
    }
    int count = cursor.getInt(0);
    cursor.close();
    return count > 0;
}

33
「SELECT 1」の方が速いと思います。
PatchyFog

cursor.getInt(0)がデータベース内のレコード数と等しいのはなぜですか?
Semyon Danilov 2014年

1
TABLEがsqliteスキーマに現れる回数をカウントしています。カウント0は、テーブルが存在しないことを意味します。カウント1は、テーブルが存在することを意味します。これらは、countの2つの予期される値のみです。
Stephen Quan 2014年

1
数値(からCOUNT(*))は処理が簡単ですが、行の存在を返すかどうかはさらに簡単です。行がある場合は存在し、行がない場合は存在しません。(moveToFirstで失敗を既に確認しているので、その時点で作業が行われます。)
dash-tom-bang

falseを返す前に、コードを更新してカーソルを閉じてください。
デイブトーマス

43

あなたは試すことができます:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = tableは便利です
mafu 2012年

C#を使用している場合、このコマンドを使用していないSQLiteReader reader = cmd.ExecuteReader();とんdt.Load(reader)(どこdtDataTable)。テーブルが見つからない場合、このObject reference is not an instance of an object例外が発生することが.Load()わかりました。代わりに、使用しSQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); てみませんかadapter.Fill(ds)、どこdsですDataSet。その後、そうであるかどうかds.Tables.Count > 0を確認できますreturn ds.Tables[0];(またはelse return null)。それDataTableからnull、あるかどうかdt.Rows != null、そしてあるかどうかを確認できますdt.Rows.Count>0
vapcguy

34

使用する:

PRAGMA table_info(your_table_name)

結果のテーブルが空の場合your_table_nameは存在しません。

ドキュメンテーション:

PRAGMA schema.table_info(table-name);

このプラグマは、名前付きテーブルの列ごとに1行を返します。結果セットの列には、列名、データ型、列をNULLにできるかどうか、および列のデフォルト値が含まれます。結果セットの「pk」列は、主キーの一部ではない列の場合はゼロであり、主キーの一部である列の場合は主キーの列のインデックスです。

table_infoプラグマで指定されたテーブルもビューにすることができます。

出力例:

cid|name|type|notnull|dflt_value|pk
0|id|INTEGER|0||1
1|json|JSON|0||0
2|name|TEXT|0||0

これは、テーブルがPythonに存在するかどうかを判断するための優れた方法です。
Michael Murphy

またはXamarinフォーム
SerenityNow

4
これは、列の定義をプログラムで取得するための優れた方法です
w00t

33

SQLiteテーブル名では大文字と小文字が区別されませんが、比較ではデフォルトで大文字と小文字が区別されます。すべてのケースでこれを正しく機能させるには、を追加する必要がありますCOLLATE NOCASE

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE

33

「テーブルが既に存在します」というエラーが発生する場合は、SQL文字列を次のように変更します。

CREATE table IF NOT EXISTS table_name (para1,para2);

これにより、例外を回避できます。



23

あなたが使用している場合FMDBを、私はあなただけことができると思いFMDatabaseAdditionsをインポートし、ブール関数を使用します。

[yourfmdbDatabase tableExists:tableName].

1
このメソッドを使用するには、必ず「FMDatabaseAdditions.h」をインポートしてください。インポートしないと、なぜ削除されたのか不思議に思うでしょう。:)
ウィル

これは正解かもしれませんが、問題は、特定の言語の特定のライブラリではなく、sqliteに関するものでした。答えは、ライブラリのメソッドの1つを呼び出すのではなく、SQLコードを提供することだと思います
nacho4d

13

次のコードは、テーブルが存在する場合は1を返し、テーブルが存在しない場合は0を返します。

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"

1
where条件が結果を妨げるので、テーブルが存在しない場合でも、これは何も返しません。
David Gausmann

10

TEMPデータベースにテーブルが存在するかどうかを確認するには、のsqlite_temp_master代わりにを使用する必要があることに注意してくださいsqlite_master

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';

9

これが私が使った関数です:

SQLDatabaseオブジェクト= dbの場合

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}

1
残念なことに、Samsungデバイスは他の誰もが使用している標準のsqlite_masterテーブル構造を使用していないことがわかり、Androidアプリでこれを使用する必要がありました。
Anthony Chuinard

7

このコードを使用してください:

SELECT name FROM sqlite_master WHERE type='table' AND name='yourTableName';

返された配列カウントが1に等しい場合、それはテーブルが存在することを意味します。それ以外の場合は存在しません。


4
class CPhoenixDatabase():
    def __init__(self, dbname):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def is_table(self, table_name):
        """ This method seems to be working now"""
        query = "SELECT name from sqlite_master WHERE type='table' AND name='{" + table_name + "}';"
        cursor = self.conn.execute(query)
        result = cursor.fetchone()
        if result == None:
            return False
        else:
            return True

注:これは現在、Python 3.7.1を搭載したMacで動作しています。


これは他のすべての回答よりもきれいに見えます。
Harsha Vardhan

私にはうまくいきません:table_nameの{}括弧を消去する必要があります。
バナナ

1
table_name切り詰められていないソース(ユーザー入力など)から提供されていないことを確認してください。そうでない場合、SQLインジェクションに対して脆弱になります。テキスト操作テクニックではなく、常にパラメータを使用することをお
勧めし

3

使用する

SELECT 1 FROM table LIMIT 1;

すべてのレコードが読み取られないようにします。


テーブルは存在するがレコードがない場合、これはNULLを返します。
radiospiel

テーブルが存在しない場合、エラーがスローされます。それをキャッチすれば、あなたはそれが存在しないことを知っています。
ラッキードナルド、2015

エラー処理をフロー制御として使用することは、通常、ベストプラクティスとは見なされていません。これはおそらく避けるべきです。
Jeff Woodard、2016年

3

次のクエリを記述して、テーブルの存在を確認できます。

SELECT name FROM sqlite_master WHERE name='table_name'

ここで「table_name」は、作成したテーブルの名前です。例えば

 CREATE TABLE IF NOT EXISTS country(country_id INTEGER PRIMARY KEY AUTOINCREMENT, country_code TEXT, country_name TEXT)"

そしてチェック

  SELECT name FROM sqlite_master WHERE name='country'

6
これは、9年前にすでに受け入れられているトップ投票の回答とどう違うのですか?
Kevin Van Dyck

3

SQLite 3を使用している最新のsqlite-net-pcl nugetパッケージ(1.5.231)を使用して、現在C#で見つけた最も信頼できる方法は次のとおりです。

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}

2

単純なSELECTクエリを使用することは-私の意見では-非常に信頼できます。何よりも、多くの異なるデータベースタイプ(SQLite / MySQL)でテーブルの存在を確認できます。

SELECT 1 FROM table;

クエリが成功したかどうかを判断するために他の信頼できるメカニズムを使用できる場合(たとえば、Qtの QSqlQueryを介してデータベースにクエリを実行する場合)は意味があります。


1

c ++関数は、dbとすべての接続されたデータベースをチェックして、テーブルと(オプションで)列の存在を確認します。

bool exists(sqlite3 *db, string tbl, string col="1")
{
    sqlite3_stmt *stmt;
    bool b = sqlite3_prepare_v2(db, ("select "+col+" from "+tbl).c_str(),
    -1, &stmt, 0) == SQLITE_OK;
    sqlite3_finalize(stmt);
    return b;
}

編集:最近発見されたsqlite3_table_column_metadata関数。したがって

bool exists(sqlite3* db,const char *tbl,const char *col=0)
{return sqlite3_table_column_metadata(db,0,tbl,col,0,0,0,0,0)==SQLITE_OK;}

public static boolean tableExists(SQLiteDatabase database、String tableName){return database.rawQuery( "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'"、null).moveToFirst(); }
ニック

文字列の連結がすべてになってしまう可能性があるため、非常に非効率的で危険な方法です。
Andrea Moro

0

これはSQLite Cordovaの私のコードです:

get_columnNames('LastUpdate', function (data) {
    if (data.length > 0) { // In data you also have columnNames
        console.log("Table full");
    }
    else {
        console.log("Table empty");
    }
});

そしてもう1つ:

function get_columnNames(tableName, callback) {
    myDb.transaction(function (transaction) {
        var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
        transaction.executeSql(query_exec, [], function (tx, results) {
            var columnNames = [];
            var len = results.rows.length;
            if (len>0){
                var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
                for (i in columnParts) {
                    if (typeof columnParts[i] === 'string')
                        columnNames.push(columnParts[i].split(" ")[0]);
                };
                callback(columnNames);
            }
            else callback(columnNames);
        });
    });
}

0

このディスカッションは、たとえ古いものでも、2セントだと思いました。このクエリは、テーブルが存在する場合はスカラー1を返し、それ以外の場合は0を返します。

select 
    case when exists 
        (select 1 from sqlite_master WHERE type='table' and name = 'your_table') 
        then 1 
        else 0 
    end as TableExists

0

テーブルが存在するか、データベース内に迅速にありません

func tableExists(_ tableName:String) -> Bool {
        sqlStatement = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(tableName)'"
        if sqlite3_prepare_v2(database, sqlStatement,-1, &compiledStatement, nil) == SQLITE_OK {
            if sqlite3_step(compiledStatement) == SQLITE_ROW {
                return true
            }
            else {
                return false
            }
        }
        else {
            return false
        }
            sqlite3_finalize(compiledStatement)
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.