Search code examples
javasqliteandroid-sqlite

SQLite delete a row and move all other rows up


This might be impossible but I couldn't seem to find a clear answer. When I delete a row in my database I want the other row's IDs to essentially move up, so if I deleted row 2, then row 3's ID would become 2. Is this possible? I am using AUTOINCREMENT so didn't know if there was almost a reverse of that?

Here is my full SQLite Code.

public class ProfileDatabaseHelper extends SQLiteOpenHelper {

    public static final String PROFILE_TABLE = "PROFILE_TABLE";
    public static final String PROFILE_ID = "ID";
    public static final String PROFILE_IMAGE = "PROFILE_IMAGE";
    public static final String RADAR_DATA_ONE = "DATA_ONE";
    public static final String RADAR_DATA_TWO = "DATA_TWO";
    public static final String RADAR_DATA_THREE = "DATA_THREE";
    public static final String RADAR_DATA_FOUR = "DATA_FOUR";
    public static final String RADAR_DATA_FIVE = "DATA_FIVE";
    public static final String RADAR_DATA_SIX = "DATA_SIX";

    public ProfileDatabaseHelper(@Nullable Context context) {
        super(context, "profiles.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String createTableStatement = "CREATE TABLE " + PROFILE_TABLE + " (" + PROFILE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + PROFILE_IMAGE + " TEXT, "
                + RADAR_DATA_ONE + " INT, " +  RADAR_DATA_TWO + " INT, " + RADAR_DATA_THREE + " INT, " + RADAR_DATA_FOUR + " INT, " + RADAR_DATA_FIVE
                + " INT, " + RADAR_DATA_SIX + " INT)";

        db.execSQL(createTableStatement);


    }

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

    }

    public boolean updateData(Integer id,String profilePhoto,Integer dataOne, Integer dataTwo, Integer dataThree, Integer dataFour, Integer dataFive, Integer dataSix){
        SQLiteDatabase db=this.getWritableDatabase();
        ContentValues contentValues=new ContentValues();
        contentValues.put(PROFILE_ID,id);
        contentValues.put(PROFILE_IMAGE,profilePhoto);
        contentValues.put(RADAR_DATA_ONE,dataOne);
        contentValues.put(RADAR_DATA_TWO,dataTwo);
        contentValues.put(RADAR_DATA_THREE,dataThree);
        contentValues.put(RADAR_DATA_FOUR,dataFour);
        contentValues.put(RADAR_DATA_FIVE,dataFive);
        contentValues.put(RADAR_DATA_SIX,dataSix);
        db.update(PROFILE_TABLE,contentValues,"ID = ?",new String[] {id.toString()});
        return true;

    }


    public boolean addOne(ProfileModel profileModel){

        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues cv = new ContentValues();

        cv.put(PROFILE_IMAGE, profileModel.getProfilePhoto());
        cv.put(RADAR_DATA_ONE, profileModel.getDataOne());
        cv.put(RADAR_DATA_TWO, profileModel.getDataTwo());
        cv.put(RADAR_DATA_THREE, profileModel.getDataThree());
        cv.put(RADAR_DATA_FOUR, profileModel.getDataFour());
        cv.put(RADAR_DATA_FIVE, profileModel.getDataFive());
        cv.put(RADAR_DATA_SIX, profileModel.getDataSix());

        long insert = db.insert(PROFILE_TABLE, null, cv);
        if (insert == -1){
            return false;
        }
        else{
            return true;
        }
    }

    public Cursor alldata(){
        SQLiteDatabase dataBaseHelper = this.getWritableDatabase();
        Cursor cursor = dataBaseHelper.rawQuery("select * from PROFILE_TABLE ", null);
        return cursor;
    }

    public boolean delete(int id) {
        SQLiteDatabase db = this.getWritableDatabase();
        String queryString = "DELETE FROM " + PROFILE_TABLE + " WHERE " + PROFILE_ID + " = " + id;
        //deleting row
        Cursor cursor = db.rawQuery(queryString, null);
        if(cursor.moveToFirst()){
            return true;
        }
        else {
            return false;
        }
    }

}

Solution

  • I am using AUTOINCREMENT so didn't know if there was almost a reverse of that?

    First AUTOINCREMENT doesn't increase the rowid (or alias thereof) value rather it is a constraint (rule) that says that the rowid MUST be greater than any that have ever been allocated (if sqlite_sequence hasn't been modified outside of SQLite's management of the table).

    It is using INTEGER PRIMARY KEY that allows a value, typically 1 greater than the highest current rowid value, to be automatically assigned. However, if the value + 1 is greater than the maximum possible value (9223372036854775807) then :-

    • With AUTOINCREMENT you get an SQLITE_FULL error.
    • Without AUTOINCREMENT attempts are made to find an unused number.

    It is extremely unlikely that (9223372036854775807) will be reached/used.

    AUTOINCREMENT is less efficient as it has to record the highest ever assigned rowid and does so by using the sqlite_sequence table. In the SQLite documentation it says :-

    The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.

    It is a very bad idea to utilise the rowid or an alias thereof for anything other than it's intended use that is for unique identifying a row from another row such as when forming a relationship, updating or deleting a row.

    • e.g. what if you sort (ORDER BY) the data by another column or columns other than the ID column? Does the id have any meaning to a user of the App?

    However, even though this it NOT recommended, the following would do what you wish :-

    private void rationaliseCol1Values() {
        ContentValues cv = new ContentValues();
        Cursor csr = mDB.query(PROFILE_TABLE,null,null,null,null,null,PROFILE_ID + " ASC");
    
        int rowcount = csr.getCount();
        long expected_id = 1;
        long current_id;
        String where_clause = PROFILE_ID + "=?";
        String[] args = new String[1];
    
        while (csr.moveToNext()) {
            current_id = csr.getLong(csr.getColumnIndex(PROFILE_ID));
            if (current_id != expected_id) {
                cv.clear();
                cv.put(PROFILE_ID,expected_id);
                args[0] = String.valueOf(current_id);
                mDB.update(PROFILE_TABLE,cv,where_clause,args);
            }
            expected_id++;
        }
        csr.close();
        // Now adjust sqlite_sequence
        where_clause = "name=?";
        args[0] = PROFILE_TABLE;
        cv.clear();
        cv.put("seq",String.valueOf(rowcount));
        mDB.update("sqlite_sequence",cv,where_clause,args);
    }