如何在Android SQLite数据库中添加新列?

92

我在Android的SQLite数据库中遇到了一个问题。

我有一张表,其中包含一个字段:StudentFname。 当应用程序在Android 2.3.1上运行良好时,如果我添加另一个字段,则我的应用程序无法正常工作。

有谁能帮帮我,他们对数据库非常了解呢?

13个回答

201

您可以在onUpgrade()方法中使用ALTER TABLE函数,就像这样:


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // If you need to add a column
  if (newVersion > oldVersion) {
     db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER DEFAULT 0");
  }
}

显然,SQLite将根据列定义而有所不同。


1
嗨!我已经尝试过了,我使用了升级方法,并在其中放置了alter table查询。但是,我仍然无法向数据库添加新列。但是,当我编写一个查询来添加新列并重命名数据库和表名时,我就能够添加新列了。但是,使用alter table方法我无法做到这一点。重命名数据库和表不是期望的任务。它应该能够使用alter table正常工作。但是我仍然无法使用alter table方法实现它。 - Aamirkhan
@NagarjunaReddy 抱歉回复晚了。你可以使用这个方法: db.execSQL("UPDATE table SET key = key + 1 WHERE name=?", new String[] {name}); - DevYudh
3
别忘了增加数据库版本号,否则 onUpgrade() 方法将不会被调用。在下面的代码中增加版本号,该代码将出现在继承 SQLiteOpenHelper 类的类的构造函数中。 super(Context context, String name, CursorFactory factory, int newVersion) - appdroid
应用程序冻结,我在日志窗口收到许多类似的消息:数据库'+data+user+0+com..._db'的连接池无法向线程1 (主线程) 授予带有标志0x5的连接。为什么会发生这种情况? - Mahdi
1
这里的条件 if (newVersion > oldVersion) 是不必要的,因为只有当新版本大于旧版本时,onUpgrade 才会被调用。 - beginner

33

在我自己的应用程序需要帮助时,我看到了这个线程,但发现许多答案存在问题。我建议采取以下措施:

private static final String DATABASE_ALTER_TEAM_1 = "ALTER TABLE "
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " string;";

private static final String DATABASE_ALTER_TEAM_2 = "ALTER TABLE "
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " string;";

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion < 2) {
         db.execSQL(DATABASE_ALTER_TEAM_1);
    }
    if (oldVersion < 3) {
         db.execSQL(DATABASE_ALTER_TEAM_2);
    }
}

你希望确保代码在用户升级超过1个版本时能正常工作,并且更新语句只运行所需的一个升级。想要了解更多,请查看这篇博客


1
如果我们想创建具有默认字符串值的更改列,该怎么办? - Shridutt Kothari

23

最简单的方法是在你的SQLiteOpenHelper类onUpgrade()方法中添加一些SQL。例如:

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

    // If you need to add a new column
    if (newVersion > oldVersion) {
        db.execSQL("ALTER TABLE student ADD COLUMN student_rollno INTEGER DEFAULT 0");
    }
}

我已经尝试过这个方法,但在升级方法中仍然无法使用alter table方法添加新列。 - Aamirkhan
嗨!我已经尝试过这个了,我使用了升级方法,并在其中放置了alter table查询。但是,我仍然无法向数据库添加新列。但是,当我编写一个查询来添加新列并重命名数据库和表名时,我就能够添加新列了。但是,使用alter table方法我无法做到这一点。重命名数据库和表不是期望的任务。它应该能够使用alter table正常工作。但是我仍然无法使用alter table方法实现它。 - Aamirkhan
@user370305,如果是第一次安装应用程序的新用户,我是否需要在表格创建语句中添加新列? - Ahesanali Suthar

16

或许可以使用 switch 代替 if/then,以更加优雅的方式从任何模式升级到最新模式。

这里也有一个不错的页面介绍修改表语法:http://alvinalexander.com/android/sqlite-alter-table-syntax-examples

public static final String TABLE_TEAM = "team";
public static final String COLUMN_COACH = "coach";
public static final String COLUMN_STADIUM = "stadium";


private static final String DATABASE_ALTER_TEAM_TO_V2 = "ALTER TABLE "
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " TEXT;";

private static final String DATABASE_ALTER_TEAM_TO_V3 = "ALTER TABLE "
    + TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " TEXT;";


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

    switch (oldVersion)
    {
        case 1:
            //upgrade from version 1 to 2
            db.execSQL(DATABASE_ALTER_TEAM_TO_V2);
        case 2:
            //upgrade from version 2 to 3
            db.execSQL(DATABASE_ALTER_TEAM_TO_V3);

        //and so on.. do not add breaks so that switch will
        //start at oldVersion, and run straight through to the latest

    }

}

这是处理多个升级的方法。检查来自哪个版本! - Ricardo
如果您直接从版本1升级到版本3(如果有人没有自动更新应用程序),则不会到达情况2。 - TyMarc
1
@TyMarc-- 是的,它会升级到版本2和3。开关使用旧版本。因此,在您的示例中,旧版本是1。然后,代码将运行case 1,从版本1升级到2,然后再运行case 2(因为没有break;),从2升级到3。所有这些都在描述中。 - E. A. Bagby

5

我已经采用了以下方法,这对我有帮助:

如果数据库版本为:6

Ex : There is a table with 5 columns

当你升级到7版本时(我正在向3个表中添加1个新列)

 1. We need to add the columns when creating a table

 2. onUpgrade method:

 if (oldVersion < 7) 
 { 
    db.execSQL(DATABASE_ALTER_ADD_PAPER_PAID);
    db.execSQL(DATABASE_ALTER_LAST_UPLOADED);
    db.execSQL(DATABASE_ALTER_PAPER_LABEL); 
 }

“DATABASE_ALTER_ADD_PAPER_PAID”是查询语句。

EX: public static final String DATABASE_ALTER_ADD_PAPER_PAID = "ALTER TABLE "
                + TableConstants.MY_PAPERS_TABLE + " ADD COLUMN " + COLUMN_PAPER_PAID + " TEXT;";

在进行以上两个操作后,对于新安装用户和应用程序升级用户来说,它将正常工作。

3

@Aamirkhan,我认为你早就解决了你在评论中提到的问题。我认为你没有增加数据库版本。否则这里的答案是直截了当的。我写这篇文章是因为它可能会帮助那些在修改表时没有增加或更改其数据库版本号的人。


是的,更改数据库名称,卸载应用程序并重新安装可以解决问题。 - Aamirkhan
@Aamirkhan,请将检查移到下一个答案,以便更清晰的解决方案可供公众使用。 - AlleyOOP

3
我认为我们不应该这样检查条件。
 if (newVersion > oldVersion) {
 }

因为如果我们使用这种方式,那么每当我们增加数据库版本时,onUpgrade() 方法都会被调用并且条件将为真,所以我们应该像这样进行检查。

if(oldVersion==1) 
{

}

因此,在此情况下,如果旧版本为2,则条件将为false,并且具有旧版本2的用户将不会更新数据库(用户仅需使用版本1),因为对于这些用户,数据库已经更新。


2

只需更改您的代码

private static final int DATABASE_VERSION = 2;

即可。


2
要向表中添加新列,您需要使用ALTER。在Android中,您可以在onUpgrade()内添加新列。
您可能会想知道,onUpgrade()如何添加新列?
当您实现SQLiteOpenHelper的子类时,您需要在类构造函数中调用超类构造函数:super(context, DB_NAME, null, 1);。我已经传递了版本1
当我将版本从1更改为大于等于2时,将调用onUpgrade()。并执行我打算进行的SQL修改。 更改版本后,我的类构造函数:
public DatabaseHelper(Context context) {
    super(context, DB_NAME, null, 2);//version changed from 1 to 2
}

像这样检查SQL修改,超类构造函数将存储的SQLite数据库文件的版本与我传递给super()的版本进行比较。如果这些(之前和现在)版本号不同,则调用onUpgrade()

代码应该如下所示:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // add new columns to migrate to version 2
    if (oldVersion < 2) { 
        db.execSQL("ALTER TABLE " + TABLE_NAME + "ADD COLUMN school VARCHAR(250)");
    }
    // add new columns to migrate to version 3
    if (oldVersion < 3) { 
        db.execSQL("ALTER TABLE " + TABLE_NAME + "ADD COLUMN age INTEGER");
    }
}

2
首先,增加数据库版本号。然后在onUpgrade方法中,您可以检查列是否已存在,如果不存在,则仅添加该列。
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   if(!existsColumnInTable(db, TABLE_NAME, COLUMN_NAME)){
      db.execSQL("ALTER TABLE foo ADD COLUMN COLUMN_NAME INTEGER DEFAULT 0");
 } 
 }

private boolean existsColumnInTable(SQLiteDatabase inDatabase, String inTable, String columnToCheck) {
    Cursor cursor = null;
    try {
        // Query 1 row
        cursor = inDatabase.rawQuery("SELECT * FROM " + inTable + " LIMIT 0", null);

        // getColumnIndex() gives us the index (0 to ...) of the column - otherwise we get a -1
        if (cursor.getColumnIndex(columnToCheck) != -1)
            return true;
        else
            return false;

    } catch (Exception Exp) {
        return false;
    } finally {
        if (cursor != null) cursor.close();
    }
}

这个方法是从这个链接提取的 在Android应用程序数据库中检查列是否存在


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