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

Sqlite 如何在表中删除后更新某些元组,sqlite,triggers,Sqlite,Triggers,我试图在SQLite中建立一个音乐流媒体服务数据库模型,我想创建一个触发器:当一首歌曲从播放列表中删除时,它后面的每首歌曲都需要将其位置递减。我真的不知道怎么写这个触发器 下面是播放列表表格的示例(很抱歉有葡萄牙语名称。idMusica=Song ID;posicao=Song在播放列表中的位置) 为了进一步解释我想要的,这里有一个例子: 如果我从播放列表1中删除歌曲6,歌曲11的位置将变为3。我相信以下操作将如您所愿:- CREATE TRIGGER IF NOT EXISTS playli

我试图在SQLite中建立一个音乐流媒体服务数据库模型,我想创建一个触发器:当一首歌曲从播放列表中删除时,它后面的每首歌曲都需要将其位置递减。我真的不知道怎么写这个触发器

下面是播放列表表格的示例(很抱歉有葡萄牙语名称。idMusica=Song ID;posicao=Song在播放列表中的位置)

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

我相信以下操作将如您所愿:-

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;
示例结果 重新订购前(第一次查询):-

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

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

如果前三首歌曲的
posicao
值为1,2,3,并且您希望在位置2添加一首歌曲,而不是更新当前的2到3、当前的3到4等等,则在当前1和2位置的
posicao
之间使用一个新值:在这种情况下为1.5

删除时,不要担心填补空白;被删除歌曲两侧的
posicao
,仍按正确顺序排列

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

SELECT idMusica, row_number() OVER (ORDER BY posicao) AS pos
FROM playlist_songs
WHERE idPlaylist = :playlistid
ORDER BY posicao
或者,每次从给定播放列表中获取一行时,只要该行是按
posicao
排序的,就只需增加程序中的一个计数器

基于窗口函数的查询,用于插入到播放列表的中间并删除,给定一个绝对位置(尽管对于删除,如果您的连接表不是没有ROWID的
,则更容易跟踪程序中歌曲的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);