【问题标题】:How to update certain tuples after deletion in a table如何在表中删除后更新某些元组
【发布时间】:2019-05-26 02:33:23
【问题描述】:

我正在尝试在 SQLite 中为音乐流服务数据库建模,我想创建这个触发器:当从播放列表中删除一首歌曲时,它之后的每首歌曲都需要减少其位置。我不太确定如何编写这个触发器。

这是播放列表表的示例(抱歉,葡萄牙语名称。idMusica = 歌曲 ID;posicao = 歌曲在播放列表中的位置)

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

【问题讨论】:

    标签: sqlite triggers


    【解决方案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;
    

    示例结果

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

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

    【讨论】:

      【解决方案2】:

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

      如果前三首歌曲的 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 排序的,就在程序中增加一个计数器。

      基于窗口函数的查询,用于插入到播放列表的中间并删除,给定一个绝对位置(虽然对于删除,如果您的联结表不是 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多