SQLiteOpenHelper onCreate()/ onUpgrade()はいつ実行されますか?


293

自分のテーブルを作成しましたSQLiteOpenHelper onCreate()が、受け取りました

SQLiteException: no such table

または

SQLiteException: no such column

エラー。どうして?

注意:

(これは、毎週数十の同様の質問をまとめた要約です。これらの質問すべてを適切な参照先に送信できるように、ここに「正規」のコミュニティWiki質問/回答を提供しようとしています。)


12
@Ndupzaこれは私の実際の問題ではなく、同じ答え/コメントをN回目に書くことにうんざりしているだけです。
laalto 2014

回答:


352

SQLiteOpenHelper onCreate()そしてonUpgrade()、データベースが実際の呼び出しによって、たとえば、開かれたときにコールバックが呼び出されますgetWritableDatabase()。データベースヘルパーオブジェクト自体が作成されるとき、データベースは開かれません。

SQLiteOpenHelperデータベースファイルをバージョン管理します。バージョン番号はintコンストラクタに渡される引数です。データベースファイルでは、バージョン番号はに格納されていPRAGMA user_versionます。

onCreate()データベースファイルが存在せず、作成された直後にのみ実行されます。場合はonCreate()リターンが正常に(例外をスローしません)、データベースが要求されたバージョン番号を使用して作成されるものとします。暗示として、SQLExceptionsをonCreate()自分で捕まえてはいけません。

onUpgrade()データベースファイルは存在するが、保存されているバージョン番号がコンストラクターで要求されたものよりも小さい場合にのみ呼び出されます。onUpgrade()要求されたバージョンにテーブルスキーマを更新する必要があります。

コード(onCreate())でテーブルスキーマを変更するときは、データベースが更新されていることを確認する必要があります。2つの主なアプローチ:

  1. 古いデータベースファイルを削除して、onCreate()再度実行します。これは多くの場合、インストール時にインストールされたバージョンを制御でき、データの損失が問題にならない開発時に推奨されます。データベースファイルを削除するいくつかの方法:

    • アプリケーションをアンインストールします。アプリケーションマネージャまたはadb uninstall your.package.nameシェルから使用します。

    • アプリケーションデータを消去します。アプリケーションマネージャを使用します。

  2. onUpgrade()呼び出されるようにデータベースのバージョンを増やします。より多くのコードが必要になるため、これは少し複雑になります。

    • データ損失が問題とならない開発時のスキーマのアップグレードの場合execSQL("DROP TABLE IF EXISTS <tablename>")、inを使用して既存のテーブルを削除し、を呼び出しonCreate()てデータベースを再作成できます。

    • リリースされたバージョンの場合onUpgrade()、ユーザーがデータを失うことがないように、データ移行を実装する必要があります。


2
@Laalto // onUpgrade()でのデータ移行//これについて説明してください。
bCliks 2014

2
@balaこの質問/回答の範囲外。質問がある場合は、遠慮なく質問として投稿してください。
laalto 2014

2
@Jaskeyバージョン番号はコードの番号です。つまり、コードの実行対象となるスキーマバージョンです。ファイルが古い場合(アプリの以前のバージョンのもの)、アップグレードする必要があります。
laalto 2014年

4
したがって、スキーマを変更するたびにSQLiteHelperでDBバージョンをハードコードする必要があります。これにより、古いアプリが実行され、db接続が取得されて古い場合、onCreateの代わりにonUpgradeが実行されるようになります。正しい?
Jaskey 2014年

2
ありがとうございました !これは私には理にかなっています。1.スキーマを更新するたびに、DB_VERSION変数(ハードコード)を変更する必要があります。2.でonUpdate()、すべての古いバージョンを確認し、適切にデータを移行します。そして、ユーザーが自分のアプリ(古いdbファイルを持っている)を更新onUpgradeすると、onCreate()トリガーされ、ユーザーが新しくインストールされた場合にトリガーされます。
Jaskey 2014年

97

Jaskeyの要求に従って、ここに不足しているポイントをさらに追加するには

データベースのバージョンは、SQLiteデータベースファイル内に格納されます。

catchはコンストラクタです

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

したがって、データベースヘルパーコンストラクターがname(2番目のパラメーター)で呼び出されると、プラットフォームはデータベースが存在するかどうかを確認し、データベースが存在する場合は、データベースファイルヘッダーからバージョン情報を取得して、正しいコールバックをトリガーします

以前の回答ですでに説明したように、名前のデータベースが存在しない場合は、がトリガーされますonCreate

以下の説明ではonUpgrade、例を挙げて説明します。

たとえば、最初のバージョンのアプリケーションにDatabaseHelper(拡張SQLiteOpenHelper)コンストラクターでバージョンを渡すバージョンが1あり、バージョンがとして渡される新しいソースコードでアップグレードされたアプリケーションを提供した2場合、DatabaseHelperが構築onUpgradeされると、ファイルがすでに存在することを確認することでプラットフォームがトリガーします。しかし、バージョンはあなたが渡した現在のバージョンよりも低いです。

ここで、アプリケーションの3番目のバージョンにdbバージョンを指定3する予定であるとします(dbバージョンは、データベーススキーマを変更する場合にのみ増加します)。このようなインクリメンタルアップグレードでは、コードを保守しやすくするために、各バージョンのアップグレードロジックをインクリメンタルに記述する必要があります。

以下の擬似コードの例:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  switch(oldVersion) {
    case 1:
       //upgrade logic from version 1 to 2
    case 2:
       //upgrade logic from version 2 to 3
    case 3:
       //upgrade logic from version 3 to 4
       break;
    default:
       throw new IllegalStateException(
                "onUpgrade() with unknown oldVersion " + oldVersion);
  }
}

breakcase 1との不足しているステートメントに注意してください2。これは、インクリメンタルアップグレードの意味です。

古いバージョンがある場合を言う2と、新しいバージョンがあり4、その後、ロジックからデータベースをアップグレードします23、その後に4

古いバージョンである場合は3、新たなバージョンであり4、それだけのためにアップグレードロジックを実行する34


1
代わりに、switch(newVersion)をswitch(oldVersion)にしたいと思います。newVersionが4であることを確認することもできます(5または3ではなく、ロジックは新しいバージョンが4であると想定しているため)。つまり、古いバージョンが2で、新しいバージョンが5の場合、ケース4をヒットし、3から4にアップグレードします(これはおそらく予期された動作ではないはずです)。
joe p

右-タイプミス..しかし、新しいバージョンが5の場合- >そして...それは常にIllegalStateExceptionがスローされますし、開発者がケース5を追加することによって、それを固定されます
アウン

1
ユーザーがアプリをバージョン2から3にのみアップグレードした場合はどうなりますか?その場合も、ケース4までのすべてのケースが実行されます。
Paramvir Singh 2015

6
@paramユーザーはそれを行うことができません。彼は2を最新(ここでは4)にのみアップグレードできます。
Habeeb Perwad 2015

20

onCreate()

  1. 初めてonCreate()データベースを作成するとき(つまり、データベースが存在しない場合)、渡されたバージョンでデータベースを作成します SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()メソッドは、定義したテーブルを作成し、作成した他のコードを実行します。ただし、このメソッドは、SQLiteファイルがアプリのデータディレクトリにない場合にのみ呼び出されます(/data/data/your.apps.classpath/databases)。

  3. コードを変更し、エミュレータで再起動した場合、このメソッドは呼び出されません。必要に応じてonCreate()実行するように、あなたはSQLiteデータベースファイルを削除するためにADBを使用する必要があります。

onUpgrade()

  1. SQLiteOpenHelper スーパーコンストラクタを呼び出す必要があります。
  2. このonUpgrade()メソッドは、バージョン整数がアプリで実行されている現在のバージョンより大きい場合にのみ呼び出されます。
  3. 必要に応じてonUpgrade()メソッドが呼ばれるように、あなたのコード内でバージョン番号をインクリメントする必要があります。

1
提供するソリューションについてもう少し説明を追加して、回答を詳しく説明していただけませんか?
abarisone 2015年

10

私は遅すぎるかもしれませんが、私の短くて甘い答えを共有したいと思います。 同じ問題について回答を確認してください。それは間違いなくあなたを助けます。深い仕様はもうありません。

テーブルを作成するための構文に自信がある場合は、同じテーブルに新しい列を追加するときに発生する可能性があります...

1)デバイスからアンインストールして、もう一度実行します。

または

2)設定->アプリ-> ClearData

または

3)DATABASE_VERSION「DatabaseHandler」クラスの変更(新しい列を追加した場合は、自動的にアップグレードされます)

public DatabaseHandler(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

または

4)DATABASE_NAME「DatabaseHandler」クラスを変更します(同じ問題に直面しましたが、を変更することで成功しDATABASE_NAMEました)。


自分のDBがあり、SQLiteAssetHelperクラスを使用しています。それで、私は以前にsqlスクリプトでDBを作成し、dbを作成しました。SQLiteAssetHelperを使用すると、同じバージョンのdbであるため、エミュレーターまたはデバイスからアプリをアンインストールするまで、DBをコピーできませんでした。
Behzad 2017年

4

拡張時の注意点 SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); -これはコンストラクターの最初の行を呼び出す必要があります
  2. オーバーライドonCreateおよびonUpgrade(必要な場合)
  3. onCreategetWritableDatabase()またはgetReadableDatabase()が実行されたときにのみ呼び出されます。そして、これはDBName、最初のステップで指定されたものが使用できない場合に1 回だけ呼び出されます。onCreateメソッドにテーブル作成クエリを追加できます
  4. 新しいテーブルを追加する場合DBversionは、変更してonUpgradeテーブル内のクエリを実行するか、単にアンインストールしてからアプリをインストールしてください。

3

onCreateは、テーブルの作成が必要なときに初めて呼び出されます。SQLiteDatabaseによって実行されるテーブル作成用のスクリプトを記述するこのメソッドをオーバーライドする必要があります。execSQLメソッド。初回の展開で実行した後、このメソッドは呼び出されません。

onUpgrade このメソッドは、データベースのバージョンがアップグレードされるときに呼び出されます。初めての展開では、データベースのバージョンは1で、2回目の展開では、テーブルに列を追加するなど、データベース構造に変更があったとします。データベースのバージョンが2になったとします。


2

次のようなデータベースとテーブルを作成できます

public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;

public DbHelper(Context context) {
    super(context, DBNAME, null, VERSION);
    // TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub
    db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS BookDb");
    onCreate(db);
  }
}

注:別のテーブルを作成するか、列を追加するか、そのようなテーブルを追加しない場合は、VERSIONをインクリメントするだけです


2

SQLiteデータベースは2つのメソッドをオーバーライドします

1)onCreate():このメソッドは、アプリケーションの初回起動時に1回だけ呼び出されます。だからそれは一度だけ呼びました

2)onUpgrade()このメソッドは、データベースのバージョンを変更すると呼び出され、その後、このメソッドが呼び出されます。DBスキーマの作成後に新しい列を追加するなど、テーブル構造を変更するために使用されます


1

このようなテーブルが見つからないのは、主にSQLiteOpenHelperクラスを開いていない場合でgetwritabledata()、これより前に、データベース名とバージョンを指定してmakeコンストラクターを呼び出す必要があります。またOnUpgradeSQLiteOpenHelperクラスで指定されたバージョン番号にアップグレード値がある場合に呼び出されます。

以下はコードスニペットです(列名のスペルが原因でそのような列が見つからなかった可能性があります):

public class database_db {
    entry_data endb;
    String file_name="Record.db";
    SQLiteDatabase sq;
    public database_db(Context c)
    {
        endb=new entry_data(c, file_name, null, 8);
    }
    public database_db open()
    {
        sq=endb.getWritableDatabase();
        return this;
    }
    public Cursor getdata(String table)
    {
        return sq.query(table, null, null, null, null, null, null);
    }
    public long insert_data(String table,ContentValues value)
    {
        return sq.insert(table, null, value);
    }
    public void close()
    {
        sq.close();
    }
    public void delete(String table)
    {
        sq.delete(table,null,null);
    }
}
class entry_data extends SQLiteOpenHelper
{

    public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
                      int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase sqdb) {
        // TODO Auto-generated method stub

        sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
          onCreate(db);
    }

}

1

「名前」文字列をコンストラクタの2番目の引数として指定するのを忘れた場合は、アプリを閉じると消去される「メモリ内」データベースが作成されます。


0

エミュレーターまたはデバイスからアプリケーションをアンインストールします。アプリをもう一度実行します。(データベースが既に存在する場合、OnCreate()は実行されません)



0

ur DatabaseHandler / DatabaseManagerクラスでクエリを再確認します(これまでに実行したもの)


0

私の場合<string-array><item>s を格納するでXMLファイルからアイテムを取得します。これら<item>のsでは、SQL文字列を保持し、で1つずつ適用しdatabaseBuilder.addMigrations(migration)ます。私は1つの間違いを犯しました、\引用の前に追加するのを忘れて、例外を得ました:

android.database.sqlite.SQLiteException:そのような列はありません:some_value(コード1 SQLITE_ERROR):、コンパイル中:INSERT INTO table_name(id、name)VALUES(1、some_value)

したがって、これは正しいバリアントです:

<item>
    INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>

-2

Sqliteopenhelperのメソッドにはcreateとupgradeメソッドがあり、テーブルが初めて作成されるときにcreateが使用され、テーブルの列数が変更されるたびにアップグレードメソッドが呼び出されます。


onUpgradeメソッドは、列の数が変更されたときではなく、データベースのバージョンが増加したときに呼び出されます。参照:developer.android.com/reference/android/database/sqlite/…、int、int
Roger Huang
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.