2013-11-09 118 views
0

(編輯:我已經想出了我的問題的答案。這個問題仍然存在,因爲某些原因,我必須等待2天才能回答我自己的問題。)Android:ALTER TABLE ADD COLUMN仍然會導致錯誤「table ... has no column named ...」

我正在開發一個將數據本地保存到SQLite數據庫的Android應用程序。我想通過添加列來更新代碼中的表模式,而不必刪除已保存在那裏的數據,所以我正在使用ALTER TABLE ADD COLUMN。

這些都是確切的SQL字符串我通過db.ExecSQL執行(通過logcat的印刷):

ALTER TABLE quests ADD COLUMN recurrence TEXT; 
ALTER TABLE quests ADD COLUMN rec_comp_date TEXT; 

只有當不存在,我添加這些列,即

// If there's no recurrence column: Add it 
if (cursor.getColumnIndex(QuestFeedEntry.COLUMN_NAME_RECURRENCE) == -1) { 
    System.out.println("Adding recurrence column"); 
    query = ("ALTER TABLE " + QuestFeedEntry.TABLE_NAME 
      + " ADD COLUMN " + QuestFeedEntry.COLUMN_NAME_RECURRENCE 
      + TEXT_TYPE + ";"); 

    System.out.println(query); 
    db.execSQL(query); 
} 

// If there's no rec_comp_date column: Add it 
if (cursor.getColumnIndex(QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE) == -1) { 
    System.out.println("Adding recurrence date column"); 
    query = ("ALTER TABLE " + QuestFeedEntry.TABLE_NAME 
      + " ADD COLUMN " + QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE 
      + TEXT_TYPE + ";"); 
    System.out.println(query); 
    db.execSQL(query); 
} 

然而,當應用程序啓動時,當我嘗試保存的東西到這些新的專欄中,我得到這些錯誤消息後,我執行這些查詢:

11-09 18:24:04.228: E/SQLiteLog(1763): (1) table quests has no column named recurrence 
11-09 18:24:04.288: E/SQLiteDatabase(1763): Error inserting recurrence=NONE stat_type=STRENGTH description= name=a difficulty=EASY rec_comp_date=null deadline=null completed=0 
11-09 18:24:04.288: E/SQLiteDatabase(1763): android.database.sqlite.SQLiteException: table quests has no column named recurrence (code 1): , while compiling: INSERT INTO 
quests(recurrence,stat_type,description,name,difficulty,rec_comp_date,deadline,completed) VALUES (?,?,?,?,?,?,?,?) 

下面是我使用的數據庫類:

//Helper class for quest-related database queries. 
public class QuestDatabase extends SQLiteOpenHelper { 

    /* Inner class that defines the table contents */ 
    public static abstract class QuestFeedEntry implements BaseColumns { 
     public static final String TABLE_NAME = "quests"; 
     public static final String COLUMN_NAME_QUEST_NAME = "name"; 
     public static final String COLUMN_NAME_QUEST_DESC = "description"; 
     public static final String COLUMN_NAME_QUEST_TYPE = "stat_type"; 
     public static final String COLUMN_NAME_QUEST_DIFFICULTY = "difficulty"; 
     public static final String COLUMN_NAME_IS_COMPLETED = "completed"; 
     public static final String COLUMN_NAME_DEADLINE = "deadline"; 
     public static final String COLUMN_NAME_RECURRENCE = "recurrence"; 
     public static final String COLUMN_NAME_REC_COMP_DATE = "rec_comp_date"; 
    } 

    private final String TEXT_TYPE = " TEXT"; 
    private final String COMMA_SEP = ","; 
    private final String SQL_CREATE_ENTRIES = "CREATE TABLE IF NOT EXISTS " 
      + QuestFeedEntry.TABLE_NAME + " (" + QuestFeedEntry._ID 
      + " INTEGER PRIMARY KEY," + QuestFeedEntry.COLUMN_NAME_QUEST_NAME 
      + TEXT_TYPE + COMMA_SEP + QuestFeedEntry.COLUMN_NAME_QUEST_DESC 
      + TEXT_TYPE + COMMA_SEP + QuestFeedEntry.COLUMN_NAME_QUEST_TYPE 
      + TEXT_TYPE + COMMA_SEP 
      + QuestFeedEntry.COLUMN_NAME_QUEST_DIFFICULTY + TEXT_TYPE 
      + COMMA_SEP + QuestFeedEntry.COLUMN_NAME_IS_COMPLETED + TEXT_TYPE 
      + COMMA_SEP + QuestFeedEntry.COLUMN_NAME_DEADLINE + TEXT_TYPE 
      + ")"; 

    private final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " 
      + QuestFeedEntry.TABLE_NAME; 

    // If you change the database schema, you must increment the database 
    // version. 
    public static final int DATABASE_VERSION = 1; 
    public static final String DATABASE_NAME = "FeedReader.db"; 

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

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL(SQL_CREATE_ENTRIES); 
    } 

    // Call this from code whenever you changed the database structure in code 
    // and need it recreated. 
    public void dropTable(SQLiteDatabase db) { 
     db.execSQL(SQL_DELETE_ENTRIES); 
     onCreate(db); 
    } 

    // This method will add any columns to the database that don't exist. 
    // These won't wipe out the current data stored, so don't need to worry 
    // about backing up data. 
    public void updateColumns(SQLiteDatabase db) { 

     Cursor cursor = db.rawQuery("SELECT * FROM " 
       + QuestFeedEntry.TABLE_NAME + " LIMIT 0", null); 

     String query = ""; 

     // If there's no deadline column: add it 
     if (cursor.getColumnIndex(QuestFeedEntry.COLUMN_NAME_DEADLINE) == -1) { 
      db.execSQL("ALTER TABLE " + QuestFeedEntry.TABLE_NAME 
        + " ADD COLUMN " + QuestFeedEntry.COLUMN_NAME_DEADLINE 
        + TEXT_TYPE + ";"); 
     } 

     // If there's no recurrence column: Add it 
     if (cursor.getColumnIndex(QuestFeedEntry.COLUMN_NAME_RECURRENCE) == -1) { 
      System.out.println("Adding recurrence column"); 
      query = ("ALTER TABLE " + QuestFeedEntry.TABLE_NAME 
        + " ADD COLUMN " + QuestFeedEntry.COLUMN_NAME_RECURRENCE 
        + TEXT_TYPE + ";"); 

      System.out.println(query); 
      db.execSQL(query); 
     } 

     // If there's no rec_comp_date column: Add it 
     if (cursor.getColumnIndex(QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE) == -1) { 
      System.out.println("Adding recurrence date column"); 
      query = ("ALTER TABLE " + QuestFeedEntry.TABLE_NAME 
        + " ADD COLUMN " + QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE 
        + TEXT_TYPE + ";"); 
      System.out.println(query); 
      db.execSQL(query); 
     } 

    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     // This database is only a cache for online data, so its upgrade policy 
     // is 
     // to simply to discard the data and start over 
     // db.execSQL(SQL_DELETE_ENTRIES); 
     // onCreate(db); 
    } 

    @Override 
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     // onUpgrade(db, oldVersion, newVersion); 
    } 
} 

這裏有兩種方法我使用,使這一類電話:

的方法從任務表1個加載數據,被稱爲中的onCreate ()的主要活動。

public void loadQuestsFromDatabase(Activity activity) { 

    if (quests == null) { 
     quests = new ArrayList<Quest>(); 
    } 

    QuestDatabase mDbHelper = new QuestDatabase(activity); 
    Log.i("Debug:", "1"); 
    SQLiteDatabase db = mDbHelper.getReadableDatabase(); 
    Log.i("Debug:", "2"); 

    mDbHelper.onCreate(db); 

    // Make sure current database is up to date by updating the columns. 
    mDbHelper.updateColumns(db); 

    // Define a projection that specifies which columns from the database 
    // you will actually use after this query. 
    String[] projection = { QuestFeedEntry.COLUMN_NAME_QUEST_NAME, 
      QuestFeedEntry.COLUMN_NAME_QUEST_DESC, 
      QuestFeedEntry.COLUMN_NAME_QUEST_TYPE, 
      QuestFeedEntry.COLUMN_NAME_QUEST_DIFFICULTY, 
      QuestFeedEntry.COLUMN_NAME_IS_COMPLETED, 
      QuestFeedEntry.COLUMN_NAME_DEADLINE, 
      QuestFeedEntry.COLUMN_NAME_RECURRENCE, 
      QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE }; 

    Log.i("Debug:", "3"); 
    Cursor cursor = db.query(QuestFeedEntry.TABLE_NAME, // The table to 
                 // query 
      projection, // The columns to return 
      null, // The columns for the WHERE clause 
      null, // The values for the WHERE clause 
      null, // don't group the rows 
      null, // don't filter by row groups 
      null // The sort order 
      ); 
    Log.i("Debug:", "4"); 
    cursor.moveToFirst(); 
    quests.clear(); 
    while (!cursor.isAfterLast()) { 
     String name = cursor.getString(0); 
     String desc = cursor.getString(1); 
     StatType type = StatType.stringToType(cursor.getString(2)); 
     QuestDifficulty diff = QuestDifficulty.stringToDifficulty(cursor 
       .getString(3)); 
     int completed = cursor.getInt(4); 
     String deadlineStr = cursor.getString(5); 
     Recurrence rec = Recurrence.NONE; 
     String recStr = cursor.getString(6); 
     if (recStr != null) { 
      rec = Recurrence.stringToRecurrence(cursor.getString(6)); 
     } 

     String recDateStr = cursor.getString(7); 

     DateTime deadline = null; 
     if (deadlineStr != null) { 
      deadline = new DateTime(deadlineStr); 
     } 
     DateTime recCompDate = null; 
     if (recDateStr != null) { 
      recCompDate = new DateTime(recDateStr); 
     } 

     Log.i("Debug:", "Loaded quest '" + name + "' from database:"); 
     Log.i("Debug:", " Name= '" + name); 
     Log.i("Debug:", " Description= '" + desc); 
     Log.i("Debug:", " Quest Type= '" + diff.toString()); 
     Log.i("Debug:", " Difficulty= '" + type.toString()); 
     Log.i("Debug:", " Completed= '" + Integer.toString(completed)); 
     Log.i("Debug:", " Recurrence = " + rec.toString()); 

     if (recCompDate != null) { 
      Log.i("Debug:", " Rec Comp Date = " + recCompDate.toString()); 
     } else { 
      Log.i("Debug:", " Rec Comp Date = (NONE)"); 
     } 

     Quest quest = new QuestBuilder(name, desc, diff, type, rec) 
       .isComplete(completed != 0).deadline(deadline) 
       .recurCompleteDate(recCompDate).build(); 

     if (completed == 0) { 
      quests.add(quest); 
     } else { 
      completedQuests.add(quest); 
     } 

     cursor.moveToNext(); 
    } 
    // make sure to close the cursor and database when done. 
    cursor.close(); 
    db.close(); 

    Log.i("Debug:", "5"); 
} 

方法2將數據保存到任務表中,並在主活動的onPause()中調用。這種方法在倒數第二行發生錯誤。

public void saveQuestsToDatabase(Activity activity) { 

    QuestDatabase mDbHelper = new QuestDatabase(activity); 

    // Gets the data repository in write mode 
    SQLiteDatabase db = mDbHelper.getWritableDatabase(); 

    // Drop the table first so that we can recreate it with all quests 
    // loaded in the arraylist 
    mDbHelper.dropTable(db); 

    ArrayList<Quest> allQuests = getAllQuests(); 

    for (int i = 0; i < allQuests.size(); i++) { 

     Quest quest = allQuests.get(i); 

     // For now, don't save completed quests so it doesn't clog up the 
     // database when debugging. 
     if (quest.getIsComplete()) { 
      continue; 
     } 

     // Create a new map of values, where column names are the keys 
     ContentValues values = new ContentValues(); 
     values.put(QuestFeedEntry.COLUMN_NAME_QUEST_NAME, quest.getName()); 
     values.put(QuestFeedEntry.COLUMN_NAME_QUEST_DESC, 
       quest.getDescription()); 
     values.put(QuestFeedEntry.COLUMN_NAME_QUEST_TYPE, quest 
       .getStatType().toString()); 
     values.put(QuestFeedEntry.COLUMN_NAME_QUEST_DIFFICULTY, quest 
       .getDifficulty().toString()); 
     values.put(QuestFeedEntry.COLUMN_NAME_IS_COMPLETED, 
       (quest.getIsComplete() ? 1 : 0)); 

     if (quest.isTimed()) { 
      values.put(QuestFeedEntry.COLUMN_NAME_DEADLINE, quest 
        .getDeadline().toString()); 
     } else { 
      values.putNull(QuestFeedEntry.COLUMN_NAME_DEADLINE); 
     } 

     values.put(QuestFeedEntry.COLUMN_NAME_RECURRENCE, quest 
       .getRecurrence().toString()); 

     if (quest.isTempComplete()) { 
      values.put(QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE, quest 
        .getRecCompDate().toString()); 
     } else { 
      values.putNull(QuestFeedEntry.COLUMN_NAME_REC_COMP_DATE); 
     } 

     Log.i("Debug:", "Saved quest '" + quest.getName() 
       + "' in database:"); 
     Log.i("Debug:", " Name= '" + quest.getName()); 
     Log.i("Debug:", " Description= '" + quest.getDescription()); 
     Log.i("Debug:", " Quest Type= '" + quest.getStatType().toString()); 
     Log.i("Debug:", " Difficulty= '" + quest.getDifficulty().toString()); 
     Log.i("Debug:", " Completed= '" 
       + (quest.getIsComplete() ? "true" : "false")); 
     Log.i("Debug:", " Recurrence= " 
       + quest.getRecurrence().toString()); 

     if (quest.getRecCompDate() != null) { 
      Log.i("Debug:", " Rec Comp Date = " 
        + quest.getRecCompDate().toString()); 
     } else { 
      Log.i("Debug:", " Rec Comp Date = (NONE)"); 
     } 

     // Insert the new row, returning the primary key value of the new 
     // row 
     long newRowId; 
     //ERROR HAPPENS ON THIS LINE 
     newRowId = db.insert(QuestFeedEntry.TABLE_NAME, "null", values); 
    } 

    // Make sure to close the database when done 
    db.close(); 

} 
+0

錯誤消息非常明確。 –

+1

你在哪裏添加這些列?你在哪裏嘗試使用新的列?我們需要更多上下文信息。 – Szymon

回答

0

我想通了我的錯誤。我在保存到saveQuestsToDatabase()之前調用dropTable,最終重新創建表的舊版本。

+0

聽起來像你的應用程序,它非常容易出錯。祝你好運。 – JRomero

相關問題