2011-09-15 3 views
2

안드로이드 프로그램과 sqlite 데이터베이스에 문제가 있습니다. 스크롤 할 수있는 목록이있는 위젯을 만들고 있습니다. 따라서 "다음"버튼을 클릭하면 데이터베이스의 다음 행이 표시됩니다.안드로이드 SQLite 삭제 후 rowids을 변경

데이터베이스에서 항목을 삭제하고 행 ID가 누락 될 때까지 제대로 작동합니다. 나는 AUTOINCREMENT까지 ROWID를 설정해 놓았지만, 일부 데이터가 삭제 된 후에 나는 누락 된 숫자를 가지고 있으며, 그 숫자를 스크롤하려고하면 오류가 반환된다.

행이 삭제 된 후 순차 순서로 ROWID를 변경하는 다른 방법이 있는지 알고 싶었습니다. 또는 rowid를 참조하지 않고 각 행을 스크롤하는 더 좋은 방법이 있습니까?

편집 :이 내가 원유를 보인다 내 "다음"활동

@Override 
protected void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    c = this; 

    //get the shared data 
    myShared = getSharedPreferences(FILENAME, 0); 
    //gets NUM_LOC data from myShared or if that fails loads in number 1 
    myNum = myShared.getInt(NUM_LOC, 0); 

    //check to see if myNum is equal to or bigger than the total number 
    //and if it is, then set it back to one 
    FlashDataBase testDB = new FlashDataBase(this); 
    testDB.open(); 
    int testNum = testDB.getNumber(); 
    testDB.close(); 
    if(myNum >= testNum){ 
     myNum = 1; 
    } 
    else{ 
     //set to next value 
     myNum ++; 
    } 
    //set the appwidgetmanager to this context 
    awm = AppWidgetManager.getInstance(c); 

    //make a remoteviews for the widget 
    RemoteViews v = new RemoteViews(c.getPackageName(), R.layout.widget); 
    ComponentName thisWidget = new ComponentName(c, VanillaProvider.class); 

    //get word from database 
    FlashDataBase fdb = new FlashDataBase(this); 
    fdb.open(); 
    String someWord = fdb.getWord(myNum); 
    fdb.close(); 

    //store current myNum into sharedpref 
    SharedPreferences.Editor editor = myShared.edit(); 
    editor.putInt(NUM_LOC, myNum); 
    editor.commit(); 

    //change the widget's remoteviews 
    //and update the appwidgemanager 
    v.setTextViewText(R.id.middle_button, someWord); 
    awm.updateAppWidget(thisWidget, v); 

    finish(); 
} 

에 대해 가지고있는 코드입니다,하지만 난 생각하고 cursor.moveToNext()를 사용하는 방법이있다; 내 데이터베이스 클래스에 다음 번호를 얻으려면?

내 데이터베이스 클래스는 BTW 개인 정적 클래스 DbHelper 모든 도움을 {

public DbHelper(Context context) { 
     super(context, DATABASE_NAME, null, SCHEMA_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     // execute some SQL code 
     db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID 
       + " INTEGER PRIMARY KEY AUTOINCREMENT, " 
       //+ KEY_NUM + " INTEGER NOT NULL, " 
       + KEY_WORD + " TEXT NOT NULL, " 
       + KEY_MEANING + " TEXT NOT NULL);"); 
    } 

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

} 

public FlashDataBase(Context c) { 
    myContext = c; 
} 

// open our db 
public FlashDataBase open() throws SQLException { 
    myHelper = new DbHelper(myContext); 
    myDatabase = myHelper.getWritableDatabase(); 
    return this; 
} 

// and this closes it 
public void close() { 
    myHelper.close(); 
} 

public long createMethod(String word, String meaning) { 
    ContentValues cv = new ContentValues(); 
    //cv.put(KEY_NUM, num); 
    cv.put(KEY_WORD, word); 
    cv.put(KEY_MEANING, meaning); 

    // and put these strings into our database 
    // inserts the cv into the table 
    return myDatabase.insert(DATABASE_TABLE, null, cv); 
} 

public String getData() { 
    String[] columns = new String[] { KEY_ROWID, KEY_WORD, KEY_MEANING }; 

    // set a cursor to read the info 
    Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, 
      null, null); 
    String result = ""; 

    // these ints are the same as getWord's method 
    // in other words, 0 1 and 2 respectively 

    int iWord = c.getColumnIndex(KEY_WORD); 
    int iMeaning = c.getColumnIndex(KEY_MEANING); 

    for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { 
     result += c.getInt(0) + " " + c.getString(iWord) + " " + c.getString(iMeaning) + "\n"; 

    } 
    return result; 
} 
    public String getWord(long l) { 

    String[] columns = new String[] { KEY_ROWID, KEY_WORD, KEY_MEANING }; 
    Cursor c = myDatabase.query(DATABASE_TABLE, columns, KEY_ROWID + "=" 
      + l, null, null, null, null); 
    if (c != null) { 
     // since we set KEY_ROWID to itself plus Long (l), then the 
     // moveToFirst starts at L (l) ^as seen above 
     c.moveToFirst(); 
     // thats a number 1 not letter l below 
     // which is the second column, aka int iWord from the getData class 
     String word = c.getString(1); 
     return word; 
    } 
    return null; 
} 

public String getMeaning(long l) { 

    String[] columns = new String[] { KEY_ROWID, KEY_WORD, KEY_MEANING }; 
    Cursor c = myDatabase.query(DATABASE_TABLE, columns, KEY_ROWID + "=" 
      + l, null, null, null, null); 
    if (c != null) { 
     // since we set KEY_ROWID to itself plus Long (l), then the 
     // moveToFirst starts at L (l) ^as seen above 
     c.moveToFirst(); 
     // thats a number 2 below 
     // which is the second column, aka int iWord from the getData class 
     String meaning = c.getString(2); 
     return meaning; 
    } 
    return null; 
} 

public int getNumber() { 
    String[] columns = new String[] { KEY_ROWID, KEY_WORD, KEY_MEANING }; 

    // set a cursor to read the info 
    Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, 
      null, null); 
    int result = 0; 

    for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { 
     result++; 
    } 
    return result; 
} 

감사 SQLiteOpenHelper 확장이 제품은 또한

* 최종 편집 : 나는 다른 무엇보다 조금 그것을 알아 냈다 나에게 말했다. 그래서 그 대신 공유 정수의) 행의 총량보다 더 많은 경우 재설정 할 공유 정수 값의 수를 유지하고 c.moveToNext를 (사용하여 데이터베이스 클래스 자체에 루프를했다 :

public String getWord(long l) { 

    String[] columns = new String[] { KEY_ROWID, KEY_WORD, KEY_MEANING }; 
    Cursor c = myDatabase.query(DATABASE_TABLE, columns, KEY_ROWID, null, null, null, null); 
    String result; 

    c.moveToFirst(); 
    for(int i=1; i<=l; i++){ 
     if(c.isLast()){ 
      c.moveToFirst(); 
      result = c.getString(1); 
      return result; 
     } 

     c.moveToNext(); 
    } 
    result = c.getString(1); 
    return result; 
} 
+0

ID를 항상 늘리면 (공백을 채우지 않아도 됨) 생각하면됩니다. 이 코드는 전혀 문제가 아니어야하므로 코드를 게시해야합니다. –

답변

3

SQL이 자동 증가 ID를 작동시키는 방식은 행이 삭제 된 후에도 일관성을 유지하므로 ID를 순차적으로 만드는 유일한 방법은 행을 수동으로 이동하거나 행을 복사하고, 테이블을 삭제하고, 새 테이블을 만들고 행을 다시 삽입하는 것입니다.

그러나 SQL 쿼리에서 LIMIT 절을 사용하여 가져올 행의 개수와 개수를 알 수 있습니다. 당신이 17 일 (ID의 독립적 인)로 시작하는 10 개 행을 원하는 경우

SELECT * FROM `your_table` LIMIT first_row_to_fetch, number_of_rows_to_fetch 

는 예를 들어, 당신이

SELECT * FROM `your_table` LIMIT 17, 10 

편집을 사용 :이 유사한 쿼리를 사용할 수 있습니다 구체적으로 :

귀하의 경우는 LIMIT/OFFSET에 대한 추가 속성합니다 (docs 참조)로 query() 방법을 사용한다, 그래서 당신은 당신의 자신의 쿼리 문자열을 실행하지 않는 자신의 편집을 감안할 때. 이미 사용중인 query() 메서드의 오버로드는 숫자 (쉼표로 제한)를 포함하는 문자열이거나 쉼표로 구분 된 두 개의 숫자 (첫 번째는 오프셋 및 쿼리 제한 임)를 취합니다. .실제로이 당신의

Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null); 

오프셋 및 제한 위의 내 첫 번째 예제처럼 작동

Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null, "offset,limit"); 

이되는 것을 의미한다.

또한, 당신은 해 orderBy 속성에 뭔가 (단지 제한 속성 전에 하나)을 넣어 할 수 있습니다, 그래서 당신은 당신의 결과가 같은 방식으로 매번 나오는 것을 알고있다. (직접 SELECT에서 그들을 요청할 때까지 당신이 그들을 볼 수 없습니다 SQLite는 그들,하지만) 당신은 ROWID의 SQLite는 버전을 사용할 수

Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, null, KEY_ROWID, "offset,limit"); 
+0

도움에 감사드립니다. 비록 나의 최종 접근 방식이 다르더라도 그것이 장기적으로 그것을 이해하는 것을 도왔습니다 – user946723

+0

대단히 환영합니다. 내 개인적인 접근 방식은 모든 항목을 가져 와서 배열이나 무언가에 넣는 것이라고 생각합니다. 너무 많지 않은 경우. 그러나 내가 덜 도울 수있어서 기쁘다. – Flygenring

0

: 나는 결과,이에 대한 KEY_ROWID를 사용하는 것이 좋습니다 것입니다. 자동으로 증가합니다. 일부 레코드 또는 레코드 그룹을 제거한 후에는 VACUUM을 수행 할 수 있습니다.. SQLite 의 경우 VACUUM은 데이터베이스 파일을 완전히 다시 쓰고 조각화를 제거하기 때문에 매우 편리합니다. SQLite 테이블에서 데이터를 제거하는 모든 포인트, 실제로 데이터베이스 파일에있는 것은 무엇입니까? 로 표시된 더러운으로 표시됩니다. 그래서이 방법은 정확하고 등등 인덱스를 다시 작성합니다 ROWID 순서를 다시 것 또한 쓰레기 데이터 (파일의 크기가에서 줄일 수)에서 데이터베이스 파일을 청소 할 수 있도록하고 있습니다.

1

하지만 rowid에 의존해서는 안됩니다. 이 기본 제공 이름이 아닌 실제 제공된 PK 컬럼 이름을 사용하고 PK 값이 무엇인지에주의를 기울이지 않아야하며 번호 매김 순서의 갭에 대해 걱정하지 않아야합니다. PK는 행을 고유하게 식별하고 가져올 수있는 편리한 핸들입니다. where id = ?.

관련 문제