Android 更新Sqlite列以删除缺少的数字
我有一个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,但
如果我删除一个项目,是否有命令对数据重新排序,以从列中删除现在缺少的数字 例如,假设该表如下所示:
_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