2015-07-22 58 views
0

我有一個Sqlite表有一個play_order列。
如果我刪除一個項目,是否有命令重新排序數據以從列中刪除現在缺失的數字?更新Sqlite列以刪除缺失的數字

例如,假設表看起來是這樣的:

_id | play_order 
---------------- 
1 | 0 
2 | 1 
3 | 2 
4 | 3 
5 | 4 

我刪除_id 3,我想重新排序play_order所以_id 4現在有2 play_order和_id 5有3個等。 ..

我可以在Java(Android)中執行此操作,但如果可能的話,寧願在SQL中執行此操作。

我試過使用虛假的行ID,但數據是遍佈表,並可以在任何點上充滿其他隨機數據。

我也想過做一個子查詢和獲取所有的數據,但不知道我是否可以循環它或設置順序。

就Android而言,我已經考慮在contentresolver上做一個「applybatch」,但無法讓它工作。

+0

我想不出一種只用SQLite語句做到這一點的方法。也許如果你描述爲什麼你需要這樣做,也許有人可以提出一個不需要這樣做的替代方案。 – Karakuri

+1

其實,我*可以想出一種使用觸發器的方式,但我不確定這是個好主意。 – Karakuri

+0

該數據是一個播放列表。我需要play_order從0開始,隨着增加的項目數量增加。但是,當你刪除一個項目時,我需要重新排列其他項目,所以沒有差距。 我使用內置的Android內容解析器和他們的表,所以我不能改變結構。 – Eric

回答

1

刪除記錄後執行此更新語句(但在刪除記錄之前需要存儲刪除記錄的play_order)。

update yourTableName set play_order = play_order - 1 where play_order > play_order_deleted; 

yourTableName =>表
play_order_deleted =>在你刪除的記錄play_order的名稱。

+0

這是有效的,但值得一提的是,您必須先讀取要刪除的行的play_order,並且一次只需要刪除一行。 – Karakuri

+0

@Karakuri我已經提到過這個。他需要將該行的play_order刪除。 ? – dsharew

+0

你是對的,我錯過了那個部分,但是關於這個工作一次只刪除一行的部分仍然很重要。 – Karakuri

4

德勁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;"); 

,你的願望,不管這將壓縮值您隨時刪除多少行。你甚至不需要在刪除之後運行語句,這是自動完成的。

+0

確定這是更好的一個。 – dsharew

+0

這看起來不錯,但使用內置的Android內容解析器我不相信我可以編輯表結構。即使我能,我也不認爲這是個好主意。 – Eric

+0

我不明白。這是你的數據庫還是其他應用程序的數據庫? – Karakuri

1

Playlists.Members有一個靜態方法moveItem()它應該照顧更新播放列表中的播放順序。如果您知道播放列表的大小,請先嚐試將該項目移到播放列表的末尾,然後刪除該項目。

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通知當它移動的項目,所以如果你有一個Loader什麼監聽,它會被觸發。這可能是也可能不是問題。您可以通過使用applyBatch()來避免這種情況,在這種情況下,您必須自己構建移動操作。基於source code around line 1653,它應該是一個更新操作。

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