Android SQLite меняет количество строк после удаления - PullRequest
2 голосов
/ 15 сентября 2011

У меня проблемы с базой данных sqlite с помощью программы для Android. Я делаю виджет со списком, который хочу прокручивать, поэтому, когда я нажимаю кнопку «Далее», он показывает следующую строку в базе данных.

Это работает нормально, пока я не удалю что-то из базы данных, и у меня не будет номеров для моих строк У меня есть rowids, настроенный на AUTOINCREMENT, но после удаления некоторых данных у меня пропускаются номера, и при попытке прокручивать эти числа возвращается ошибка.

Я просто хотел узнать, есть ли другой способ изменить строку в последовательном порядке после удаления строки. Или есть лучший способ прокручивать каждую строку, не обращаясь к 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 (); в моем классе базы данных, чтобы получить следующий номер?

это мой класс базы данных, кстати закрытый статический класс DbHelper расширяет SQLiteOpenHelper {

    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;
}

Спасибо за помощь также

* окончательное редактирование: Я понял это немного иначе, чем то, что мне сказали; Я сохранил счет в общем целочисленном значении, которое будет сброшено, если будет превышать общее количество строк, и сделал цикл в самом классе базы данных, используя 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;
}

Ответы [ 3 ]

3 голосов
/ 15 сентября 2011

То, как SQL работает с автоинкрементным идентификатором, будет постоянным после удаления строк, поэтому единственный способ сделать идентификаторы последовательными снова - это перемещать записи вручную вокруг или копировать строки, удалять таблицу, создавать новую и вставлятьснова строки.

Однако вы можете просто использовать предложение LIMIT в своем запросе SQL, чтобы указать, какую и сколько строк вы хотите получить.Если быть точным, вы можете использовать запрос, подобный следующему:

SELECT * FROM `your_table` LIMIT first_row_to_fetch, number_of_rows_to_fetch

, например, если вы хотите 10 строк, начиная с 17-го (независимо от идентификаторов), вы должны использовать

SELECT * FROM `your_table` LIMIT 17, 10

РЕДАКТИРОВАТЬ:

Учитывая ваше собственное редактирование, вы не выполняете свою собственную строку запроса, поэтому в вашем случае вы должны использовать метод query() с добавленным атрибутом для LIMIT/OFFSET (см. документы ).Эта перегрузка метода 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 (тот, который находится непосредственно перед атрибутом limit), чтобы вы знали, что ваш результат каждый раз получается одинаковым.Я бы порекомендовал использовать для этого KEY_ROWID, в результате чего:

Cursor c = myDatabase.query(DATABASE_TABLE, columns, null, null, null, null, KEY_ROWID, "offset,limit");
1 голос
/ 15 сентября 2011

Но вы не должны полагаться на rowid. Используйте фактическое имя столбца PK, которое вы дали, а не это встроенное имя, и не обращайте внимания на значение PK и не беспокойтесь о пробелах в последовательности нумерации. PK - это просто удобный дескриптор, который позволяет однозначно идентифицировать строку и извлечь ее .... where id = ?.

0 голосов
/ 15 сентября 2011

Вы можете использовать версию SQLite ROWID (они есть у SQLite, но вы не сможете их увидеть, пока не запросите их непосредственно в SELECT ). Они автоматически увеличиваются. После удаления какой-либо записи или группы записей вы можете выполнить VACUUM; . Для SQLite VACUUM очень удобно, поскольку он полностью переписывает файл базы данных и удаляет фрагментацию. Все дело в удалении данных из таблиц SQLite, что они на самом деле все еще находятся в файле базы данных, но помечены как dirty . Таким образом, этот метод позволит вам очистить файл базы данных от мусора данных ( файл уменьшится в размере ), а также восстановит последовательность ROWID, чтобы она была правильной, и восстановит индексы и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...