由于:android.database.sqlite.SQLiteException: no such table: (code 1) Android引起。

28
我们的应用程序中有一个SQLite数据库。对于所有用户来说,它都很好用,但其中一些用户遇到了“Caused by: android.database.sqlite.SQLiteException: no such table: generalSettings (code 1): , while compiling: select * from generalSettings”错误。
以下是我的SQLite帮助类,用于创建数据库和错误日志。在“assert/Master.db”中,我们有表“generalSettings”。但将其复制到设备后,该表会丢失。这只发生在少数用户身上。我已经搜索了解决方案,但找不到确切的解决方法。团队,请帮我解决这个问题。
代码:
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.Log;

public class InstallDB extends SQLiteOpenHelper {
    Context ctx;

    String DBNAME;
    String DBPATH;
    Modules modObj = new Modules();

    public InstallDB(Context context, String name) {
        super(context, name, null, 1);
        this.ctx = context;
        this.DBNAME = name;

        this.DBPATH = this.ctx.getDatabasePath(DBNAME).getAbsolutePath();
        Log.e("Path 1", DBPATH);

    }

    public void createDataBase() {

        boolean dbExist = checkDataBase();

        SQLiteDatabase db_Read = null;

        if (!dbExist) {
            synchronized (this) {

                db_Read = this.getReadableDatabase();
                Log.e("Path 2", this.getReadableDatabase().getPath());
                db_Read.close();

                copyDataBase();
                Log.v("copyDataBase---", "Successfully");
            }

            // try {

            // } catch (IOException e) {
            // throw new Error("Error copying database");
            // }
        }
    }

    private boolean checkDataBase() {

        SQLiteDatabase checkDB = null;

        try {
            String myPath = DBPATH;
            checkDB = SQLiteDatabase.openDatabase(myPath, null,
                    SQLiteDatabase.OPEN_READWRITE);
        } catch (Exception e) {
            Log.i("SQLite Error", "database does't exist yet.");
        }

        if (checkDB != null) {
            checkDB.close();
        }

        return checkDB != null ? true : false;
    }

    private void copyDataBase() {

        try {
            InputStream myInput = ctx.getAssets().open(DBNAME);
            String outFileName = DBPATH;

            OutputStream myOutput = new FileOutputStream(outFileName);

            byte[] buffer = new byte[1024 * 3];

            int length = 0;

            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
            }

            myOutput.flush();
            myOutput.close();
            myInput.close();
        } catch (Exception e) {
            Modules.stacTaceElement = e.getStackTrace();

            StringWriter stackTrace1 = new StringWriter();
            e.printStackTrace(new PrintWriter(stackTrace1));
            System.err.println(stackTrace1);

            Intent send = new Intent(Intent.ACTION_SENDTO);
            String uriText;

            uriText = "mailto:test@test.com"
                    + "&subject=Error Report"
                    + "&body="
                    + stackTrace1.toString();

            uriText = uriText.replace(" ", "%20");
            Uri uri = Uri.parse(uriText);

            send.setData(uri);
            ctx.startActivity(Intent.createChooser(send, "Send mail..."));
            // TODO: handle exception
        }

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

错误日志:

java.lang.RuntimeException: Unable to start activity ComponentInfo{palmagent.FidelityAgent.Two/palmagent.FidelityAgent.Two.PassNew}: android.database.sqlite.SQLiteException: no such table: generalSettings (code 1): , while compiling: select * from generalSettings
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2269)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5102)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteException: no such table: generalSettings (code 1): , while compiling: select * from generalSettings
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
at palmagent.FidelityAgent.Two.masterDatabase.selectquery(masterDatabase.java:59)
at palmagent.FidelityAgent.Two.Modules.checkDatabase(Modules.java:28825)
at palmagent.FidelityAgent.Two.PassNew$LoaduserDetails.onPreExecute(PassNew.java:140)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:587)
at android.os.AsyncTask.execute(AsyncTask.java:535)
at palmagent.FidelityAgent.Two.PassNew.onCreate(PassNew.java:120)
at android.app.Activity.performCreate(Activity.java:5248)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2173)
... 11 more

你正在将已部署的数据库副本写入 Android 创建的数据库中吗?我认为这是一个不好的想法,因为 Android 在数据库本身中保存了一些私有数据。 - brummfondel
@brummfondel - 我们的数据库有10个表和一些静态数据。因此创建数据库需要很长时间,所以我们将数据库复制到了Android上。请让我知道最好的方法。 - Sniper
在测试我的应用程序时,我在一些设备和模拟器上遇到了相同的问题。http://stackoverflow.com/questions/24406326/no-such-table-in-api-2-2 - Vivek Warde
18个回答

36

问题是因为某些设备正在升级您的应用,所以 checkDataBase() 返回 true,因此您没有调用 copyDataBase()。因此,您正在使用先前的数据库,该数据库不具有 generalSettings 表。 要解决此问题,请尝试以下操作:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(newVersion>oldVersion)
  copyDatabase();
}

并且更新您的构造函数:

public InstallDB(Context context, String name) {
    super(context, name, null, DB_VERSION); 
    // DB_VERSION is an int,update it every new build

    this.ctx = context;
    this.DBNAME = name;
    this.DBPATH = this.ctx.getDatabasePath(DBNAME).getAbsolutePath();
    Log.e("Path 1", DBPATH);

}

如果这个答案解决了你的问题,请将其标记为正确答案。 - Ratul Ghosh
OnUpgrabde可以被调用,新版本实际上比旧版本低吗? - Stephane Mathis

21

经过几个小时的努力,我得到了这个解决方法:

1)设置 > 应用管理器

2)选择应用程序

3)清除数据

4)卸载应用程序

现在从Android Studio运行应用程序

希望这能正常工作


9
这只能在测试时暂时使用,但对于使用较旧版本的用户将无法使用。 - A. N
1
这肯定会让你的用户的应用程序崩溃,你将不得不告诉他们全部卸载/清除数据。这是失去用户的秘诀。其他关于执行DB升级的答案是更好的方式来解决这个问题,同时保留忠实的用户。 - yiati
我刚刚为测试重新命名了数据库名称,这样做很有帮助。在Gradle中,我的数据库模块的uninstallAll功能无法正常工作。重建项目也无效。我认为这是AS的一个bug,可能与缓存有关。 - Elron

8

这个错误发生是因为您没有使用 DATABASE_VERSION

public class DatabaseHelper extends SQLiteOpenHelper {
    private static SQLiteDatabase sqliteDb;

    private static DatabaseHelper instance;

    private static final int DATABASE_VERSION = 1;

每次对数据库进行更改时,只需将DATABASE_VERSION增加1即可提高版本号。

5

另一种可能的解决方案是从Android模拟器中卸载一个应用程序,然后再次运行它。

如果您只想删除一个应用程序:

1.Start the emulator.
2.Open the Android settings app.
3.Select "Applications" (Called "Apps" on Android 4.0 or higher)
4.Select "Manage Applications" (Only on Android 3.2 or lower)
5.Select the application you want to uninstall.
6.Click "Uninstall"

2
当您在开发过程中更改数据库结构或命名时,这是有意义的。如果您在发布之间进行了更改,则需要为用户处理升级,并且不能要求他们手动重新安装应用程序;-) - hb0

4
假设您的应用程序使用数据库版本1,如果您更改表结构或添加新表,则必须将数据库版本增加到2,如果对其进行更多更改,则必须进一步增加数据库版本。
public class AppDatabase extends SQLiteOpenHelper {

    // Database Name
    private static final String DATABASE_NAME = "myDatabase";

    // Database Version
    private static final int DATABASE_VERSION = 1;    

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

如果进行了任何更改,请增加此 DATABASE_VERSION 值。


是的,这是一个好的实践。 - Isaac Darlong

2
即使您已经编写了几个表并升级了数据库,您的应用程序也会崩溃。您需要做的是为每个表创建数据库更改并升级DATABASE_VERSION
如果您有几个DatabaseHelper类(请阅读此处),则必须将此方法添加到您的db helper中:
@Override
public void onOpen(SQLiteDatabase db) {
    onCreate(db);
}

2

更新DATABASE_VERSION并卸载应用程序。现在运行该应用程序。


是的@paul,这样我们可以进行管理,但如果我们不想卸载应用程序,那么在这种情况下我们该怎么办呢? - Vishwa Pratap

1
如果您正在使用GreenDao并遇到此错误,请确保卸载应用程序并重试。这解决了我的问题。

0
在我的情况下,我打开了“设备文件浏览器”选项卡并清除了数据库文件。
然后我运行了应用程序。
这对我起作用了。

0
请在主类中初始化复制数据库或数据库助手,像这样: Database helper = new Database(this); helper.execute(sqliteobj)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接