在表中删除后如何更新某些元组

时间:2019-05-26 02:33:23

标签: sqlite triggers

我正在尝试在SQLite中建立音乐流服务数据库的模型,我想创建此触发器:从播放列表中删除歌曲时,其后的每一首歌曲的位置都必须降低。我不太确定如何编写此触发器。

这是播放列表的一个示例(对不起,葡萄牙的名字。idMusica =歌曲ID; posicao =歌曲在播放列表中的位置)

Playlists

为了进一步解释我想要的内容,这里有一个例子: 如果我从播放列表1中删除歌曲6,则歌曲11的位置将变为3。

2 个答案:

答案 0 :(得分:1)

我相信以下内容可以满足您的要求:-

CREATE TRIGGER IF NOT EXISTS playlistreorder 
    AFTER DELETE ON playlist
    BEGIN
        UPDATE playlist SET posicao = posicao -1 WHERE posicao > old.posicao AND idPlayList = old.idPlayList;
    END
;
  • 请注意,表名已假定为播放列表

示例

请考虑以下测试:-

DROP TABLE IF EXISTS playlist;
CREATE TABLE IF NOT EXISTS playlist (idMusica INTEGER, idPlayList INTEGER, posicao INTEGER);
INSERT INTO playlist (idMusica,idPlayList, posicao) VALUES
    (12,1,1),(5,1,2),(6,1,3),(11,1,4),
    (1,2,1),(2,2,2),(3,2,2),(4,2,4),(9,2,5)
;

CREATE TRIGGER IF NOT EXISTS playlistreorder 
    AFTER DELETE ON playlist
    BEGIN
        UPDATE playlist SET posicao = posicao -1 WHERE posicao > old.posicao AND idPlayList = old.idPlayList;
    END
;
SELECT * FROM playlist;
DELETE FROM playlist WHERE posicao = 3 AND idplayList = 1;
SELECT * FROM playlist;

示例结果

重新排序之前(第一个查询):-

enter image description here

重新排序后(第二次查询):-

enter image description here

答案 1 :(得分:0)

我认为这种方法从根本上是错误的,而且过于脆弱。而不是跟踪播放列表中的绝对位置,而是跟踪相对位置。这样,您在插入或删除歌曲时就不必更新位置:

如果前三首歌曲的posicao值为1,2,3,并且您想在位置2添加歌曲,而不是将当前的2更新为3,将当前的3更新为4,依此类推,请在当前1和2位置的posicao的中间使用一个新值:在这种情况下为1.5。

删除时,不用担心填补空白;删除的歌曲两侧的posicao的顺序仍然正确。

如果出于某种原因需要绝对位置,则可以SELECT中使用现代版本的sqlite(3.25或更高版本)以及类似的内容动态计算它

SELECT idMusica, row_number() OVER (ORDER BY posicao) AS pos
FROM playlist_songs
WHERE idPlaylist = :playlistid
ORDER BY posicao

或者每次您从给定的播放列表中获取一行时,只要在程序中增加一个计数器,只要posicao对其进行排序即可。

基于窗口函数的查询,用于插入到播放列表的中间并在给定绝对位置的情况下进行删除(尽管要删除,但如果联结表不是WITHOUT ROWID的话,则跟踪列表的rowid会更容易程序中的歌曲,并使用所选歌曲中的歌曲删除):

INSERT INTO playlist_songs(idMusica, idPlaylist, posicao)
VALUES(:songid, :playlistid
     , (SELECT (pos + prev_pos) / 2.0
        FROM (SELECT posicao AS pos
                   , lag(posicao, 1, 0.0) OVER (ORDER BY posicao) AS prev_pos
                   , row_number() OVER (ORDER BY posicao) AS rn
              FROM playlist_songs WHERE idPlaylist = :playlistid)
        WHERE rn = :position));

DELETE FROM playlist_songs
WHERE rowid = (SELECT rowid
               FROM (SELECT rowid, row_number() OVER (ORDER BY posicao) AS rn
                     FROM playlist_songs WHERE idPlaylist = :playlistid)
               WHERE rn = :position);