Android 更新Sqlite列以删除缺少的数字

Android 更新Sqlite列以删除缺少的数字,android,sql,sqlite,Android,Sql,Sqlite,我有一个Sqlite表,其中有一列用于播放顺序。 如果我删除一个项目,是否有命令对数据重新排序,以从列中删除现在缺少的数字 例如,假设该表如下所示: _id | play_order ---------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 我删除了_id3,我想重新排列播放顺序,这样_id4现在有一个播放顺序2,而_id5有3等等 我可以用Java(Android)实现,但如果可能的话,我更愿意用SQL实现 我尝试过使用一个假行id,但

我有一个Sqlite表,其中有一列用于播放顺序。
如果我删除一个项目,是否有命令对数据重新排序,以从列中删除现在缺少的数字

例如,假设该表如下所示:

_id | play_order
----------------
1   | 0
2   | 1
3   | 2
4   | 3
5   | 4
我删除了_id3,我想重新排列播放顺序,这样_id4现在有一个播放顺序2,而_id5有3等等

我可以用Java(Android)实现,但如果可能的话,我更愿意用SQL实现

我尝试过使用一个假行id,但是数据遍布整个表,并且在任何时候都可能充满其他随机数据

我也想过做一个子查询并获取所有数据,但不知道是否可以循环使用它或其他东西来设置顺序


就Android而言,我已经研究过在contentresolver上执行“applybatch”,但也无法实现这一点。

删除记录后执行此更新语句(但删除记录前需要存储已删除记录的播放顺序)


yourTableName
=>表名

play\u order\u deleted
=>删除的记录的播放顺序。

删除记录后执行此更新语句(但删除前需要存储删除记录的播放顺序)


yourTableName
=>表名

play\u order\u deleted
=>您删除的记录的播放顺序。

Degen Sharew的答案很好,但这里有一个替代方案:

SQLiteOpenHelper
中,创建数据库时,运行以下语句:

db.execSQL("CREATE TRIGGER trigger_compress_play_order" +
        " AFTER DELETE ON " + TABLE_NAME + " BEGIN " + 
        " UPDATE " + TABLE_NAME + 
        " SET " + PLAY_ORDER_COLUMN + " = " + PLAY_ORDER_COLUMN + " - 1" + 
        " WHERE " + PLAY_ORDER_COLUMN + " > OLD." + PLAY_ORDER_COLUMN + "; END;");

无论您在任何时候删除多少行,这都会根据需要压缩值。您甚至不必在删除后运行语句,这会自动执行。

Degen Sharew的答案很好,但这里有一个替代方案:

SQLiteOpenHelper
中,创建数据库时,运行以下语句:

db.execSQL("CREATE TRIGGER trigger_compress_play_order" +
        " AFTER DELETE ON " + TABLE_NAME + " BEGIN " + 
        " UPDATE " + TABLE_NAME + 
        " SET " + PLAY_ORDER_COLUMN + " = " + PLAY_ORDER_COLUMN + " - 1" + 
        " WHERE " + PLAY_ORDER_COLUMN + " > OLD." + PLAY_ORDER_COLUMN + "; END;");

无论您在任何时候删除多少行,这都会根据需要压缩值。您甚至不必在删除后运行语句,这会自动执行。

播放列表。成员有一个静态方法,该方法应负责更新播放列表中的播放顺序。如果您知道播放列表的大小,请尝试先将该项目移动到播放列表的末尾,然后删除该项目

private boolean deleteFromPlayList(long playlistId, int position, int playlistSize) {
    ContentResolver cr = getContentResolver(); // or pass it in method args
    // I'm assuming play order starts at 1, but if it starts at 0, 
    // then change this check accordingly
    if (position != playlistSize) {
        // this will return true on success, in case you want to check that it moved
        Playlists.Members.moveItem(cr, playlistId, position, playlistSize);
    }
    return cr.delete(...) > 0;
}
需要注意的一点是,
moveItem()
在移动项目时会导致一个Uri通知,因此如果您有一个加载程序或其他侦听程序,它将被触发。这可能是问题,也可能不是问题。您可以通过使用
applyBatch()
来避免这种情况,在这种情况下,您必须自己构建移动操作。基于,它应该是一个更新操作

ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(2);
Uri moveUri = Playlists.Members.getContentUri("external", playlistId)
        .buildUpon()
        .appendPath(Integer.toString(position))
        .appendQueryParameter("move", "true")
        .build();
ops.add(ContentProviderOperation.newUpdate(moveUri)
        .withValue(Playlists.Members.PLAY_ORDER, playlistSize)
        .build());
Uri deleteUri = Playlists.Members.getContentUri("external", playlistId)
        .buildUpon()
        .appendPath(Long.toString(playlistMemberId))
        .build();
ops.add(ContentProviderOperation.newDelete(deleteUri).build());
contentResolver.applyBatch(MediaStore.AUTHORITY, ops);
arraylistops=新的ArrayList(2);
Uri moveUri=Playlists.Members.getContentUri(“外部”,playlistId)
.buildon()
.appendPath(整数.toString(位置))
.appendQueryParameter(“移动”、“真实”)
.build();
添加(ContentProviderOperation.newUpdate(moveUri)
.withValue(Playlists.Members.PLAY_顺序、播放大小)
.build());
Uri deleteUri=Playlists.Members.getContentUri(“外部”,playlistId)
.buildon()
.appendPath(长.toString(playlymemberId))
.build();
add(ContentProviderOperation.newDelete(deleteUri.build());
contentResolver.applyBatch(MediaStore.AUTHORITY,ops);

播放列表。成员有一个静态方法,该方法应负责更新播放列表中的播放顺序。如果您知道播放列表的大小,请尝试先将该项目移动到播放列表的末尾,然后删除该项目

private boolean deleteFromPlayList(long playlistId, int position, int playlistSize) {
    ContentResolver cr = getContentResolver(); // or pass it in method args
    // I'm assuming play order starts at 1, but if it starts at 0, 
    // then change this check accordingly
    if (position != playlistSize) {
        // this will return true on success, in case you want to check that it moved
        Playlists.Members.moveItem(cr, playlistId, position, playlistSize);
    }
    return cr.delete(...) > 0;
}
需要注意的一点是,
moveItem()
在移动项目时会导致一个Uri通知,因此如果您有一个加载程序或其他侦听程序,它将被触发。这可能是问题,也可能不是问题。您可以通过使用
applyBatch()
来避免这种情况,在这种情况下,您必须自己构建移动操作。基于,它应该是一个更新操作

ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(2);
Uri moveUri = Playlists.Members.getContentUri("external", playlistId)
        .buildUpon()
        .appendPath(Integer.toString(position))
        .appendQueryParameter("move", "true")
        .build();
ops.add(ContentProviderOperation.newUpdate(moveUri)
        .withValue(Playlists.Members.PLAY_ORDER, playlistSize)
        .build());
Uri deleteUri = Playlists.Members.getContentUri("external", playlistId)
        .buildUpon()
        .appendPath(Long.toString(playlistMemberId))
        .build();
ops.add(ContentProviderOperation.newDelete(deleteUri).build());
contentResolver.applyBatch(MediaStore.AUTHORITY, ops);
arraylistops=新的ArrayList(2);
Uri moveUri=Playlists.Members.getContentUri(“外部”,playlistId)
.buildon()
.appendPath(整数.toString(位置))
.appendQueryParameter(“移动”、“真实”)
.build();
添加(ContentProviderOperation.newUpdate(moveUri)
.withValue(Playlists.Members.PLAY_顺序、播放大小)
.build());
Uri deleteUri=Playlists.Members.getContentUri(“外部”,playlistId)
.buildon()
.appendPath(长.toString(playlymemberId))
.build();
add(ContentProviderOperation.newDelete(deleteUri.build());
contentResolver.applyBatch(MediaStore.AUTHORITY,ops);

我想不出一种只用SQLite语句就能做到这一点的方法。也许如果你描述一下你为什么需要这样做,也许有人可以建议一个不需要这样做的替代方案。实际上,我可以想出一种使用触发器的方法,但我不确定这是一个好主意。数据是一个播放列表。我需要播放顺序从0开始,并随着添加的项目数量的增加而增加。但是,当你删除一个项目,我需要重新排序所有其他东西,这样就没有差距。我使用的是内置的Android内容解析器和它们的表,所以我不能改变它的结构。我想不出一种方法来实现这一点,只使用SQLite语句。也许如果你描述一下你为什么需要这样做,也许有人可以建议一个不需要这样做的替代方案。实际上,我可以想出一种使用触发器的方法,但我不确定这是一个好主意。数据是一个播放列表。我需要播放顺序从0开始,并随着添加的项目数量的增加而增加。但是,当你删除一个项目,我需要重新排序所有其他东西,这样就没有差距。我使用的是内置的Android内容解析器及其表,因此无法更改其结构。这是可行的,不过值得一提的是,您必须首先阅读a行的
play\u order