дизайн базы данных для позиции песни в списке воспроизведения - PullRequest
0 голосов
/ 08 января 2019

У меня есть приложение для потоковой передачи музыки, в котором есть плейлисты. Каждый плейлист содержит максимум 100 песен. У меня есть таблица сопоставления с именем PlaylistSongMapping, которая имеет следующую схему

+------+------------+--------+
|SongId| PlaylistId |Position|
+------+------------+--------+
|   1  |     10     |    2   |
|   2  |     10     |    1   |
|   3  |     10     |    3   | 
|   5  |     10     |    4   | 
|   6  |     11     |    1   |
+------+------------+--------+

Положение каждой песни в списке воспроизведения управляется с помощью столбца Position. Внутри плейлиста мне нужна функциональность изменения порядка. Текущая логика - обновить столбец Position. Проблема в том, что если мне нужно переместить песню с SongId: 3 на первую позицию, мне нужно обновить строки с SongId 1,2,3. Это число будет большим, если в плейлисте будет больше песен. Есть ли лучшая логика, чтобы количество запросов на обновление было минимальным.

Ответы [ 3 ]

0 голосов
/ 08 января 2019

"Проблема в том, что мне нужно переместить песню с SongId: 3 на первый Положение мне нужно обновить строки SongId 1,2,3 "

Для этого вам не нужно более двух утверждений.

Вы можете обновить все значения позиции (кроме той, которую вы перемещаете в первую позицию) в одном утверждении, используя при необходимости увеличение / уменьшение, а затем использовать второе утверждение, чтобы обновить конкретную песню, которую вы перемещаете - например

update PlaylistSongMapping 
set Position = Position + 1 
where 
  Playlistid = 10 
  and position < 3 and position >= 1; 

update PlaylistSongMapping 
set position = 1 
where songId = 3;

Это предполагает, что вы знаете Id песни, которую вы перемещаете (и, следовательно, вы можете определить ее текущую позицию, которая вам нужна для предложения where в первом запросе), - но всегда должно быть так, что вы знаете, что на основании вашего описания.

Обратите внимание, что в приведенном выше примере position >= 1 не является строго необходимым, поскольку 1 является первой позицией в списке, но этот код призван охватить более общий случай - например, если вы хотите переместить его в позицию 2, вы не захотите включать песню в позицию 1 в приращении, поэтому в этом случае вы будете писать position >= 2.

0 голосов
/ 08 января 2019

Если вы после SP, который обновляет все соответствующие позиции в таблице при перемещении позиции, это должно сделать работу:

USE Sandbox;
GO

--Small sample set
CREATE TABLE dbo.Playlist (SongID int,
                           PlaylistID int,
                           Position int);
INSERT INTO dbo.Playlist (SongID,
                      PlaylistID,
                      Position)
VALUES(1,1,1),
      (3,1,2),
      (5,1,3),
      (2,1,4),
      (2,2,1),
      (10,2,2);
GO

--Check data
SELECT *
FROM dbo.Playlist;
GO

--CREATE the SP
CREATE PROC dbo.MoveSongPosition @PlaylistID int,
                             @SongID int,
                             @NewPosition int
AS BEGIN

    UPDATE P
    SET Position = CASE WHEN SongID = @SongID THEN @NewPosition ELSE Position +1 END
    FROM dbo.Playlist P
    WHERE P.PlaylistID = @PlaylistID
      AND (P.SongID = @SongID
       OR  P.Position BETWEEN @NewPosition AND (SELECT sq.Position
                                               FROM dbo.Playlist sq
                                               WHERE sq.SongID = @SongID
                                                 AND sq.PlaylistID = @PlaylistID));
END
GO

--Run and test the SP
EXEC dbo.MoveSongPosition @PlaylistID = 1,
                          @SongID = 2,
                          @NewPosition = 2;
GO

--Check the new data
SELECT *
FROM dbo.Playlist;
GO

--Clean up
DROP PROC dbo.MoveSongPosition;
DROP TABLE dbo.Playlist;

В этом решении предполагается, что вы используете SQL Server; вы не обновляли свои теги со времени моего комментария, поэтому мы не знаем, какие RDBM вы действительно используете.

Редактировать: изменение логики, поверь, я исправил.

CREATE PROC dbo.MoveSongPosition @PlaylistID int,
                                 @SongID int,
                                 @NewPosition int
AS BEGIN

    UPDATE P
    SET Position = CASE WHEN P.SongID = @SongID THEN @NewPosition
                        WHEN P.Position = @NewPosition THEN P.Position + V.Direction
                        WHEN P.Position < @NewPosition THEN P.Position - V.Direction
                        WHEN P.Position > @NewPosition THEN P.Position + V.Direction
                   END
    FROM dbo.Playlist P
         CROSS APPLY (SELECT ca.Position
                      FROM dbo.Playlist ca
                      WHERE ca.PlaylistID = P.PlaylistID
                        AND ca.SongID = @SongID) CS
         CROSS APPLY (VALUES(CASE WHEN CS.Position < @NewPosition THEN -1
                                  WHEN @NewPosition < CS.Position THEN 1
                                  ELSE 0 END)) V(Direction)
    WHERE P.PlaylistID = @PlaylistID
      AND ((P.Position >= @NewPosition AND P.Position <= CS.Position
       OR   (P.Position >= CS.Position AND P.Position <= @NewPosition)));
END
0 голосов
/ 08 января 2019

Теоретически более оптимально (но намного сложнее)

Если вы думаете об этом столбце как о порядке сортировки, а не как о точной позиции, у вас может быть какая-то стратегия с пробелами, нумерация будет равна 10, 20, 30. Затем, если вы хотите переместить 3-ю песню в первую положение, вы можете дать ему номер 5, или вы можете даже дать ему отрицательное число.

Проблема в том, что вам все равно нужно будет прочитать все данные, и реализация нумерации становится намного сложнее, потому что теперь вам нужно проверить, нужно ли вам ничего не обновлять, или все, или, может быть, просто часть списка.

Довольно просто (в основном то, что у вас есть сейчас)

Так что, будь я на вашем месте, я бы упростил задачу и просто обновил все, что нужно обновить. В конце концов, в списке воспроизведения не так много строк (даже если вы разрешите 1000 или более песен в списке воспроизведения), и если вы сделаете это массовое обновление, база данных сможет справиться с этим просто отлично. Вы можете сдвинуть все строки одновременно, а затем обновить одну строку до ее новой позиции. Таким образом, вам понадобятся только два оператора: 1 для вставки, обновления или удаления определенной песни и 1 для смещения всего или части списка, чтобы сохранить нумерацию после.

Очень просто (и, вероятно, все еще достаточно быстро)

В прошлом я реализовывал это еще более ленивым образом, где я сохранял порядок сортировки с пробелом, имеющий 2, 4, 6, 8 ... Затем, когда я хотел обновить или вставить в определенный положение, я мог бы просто использовать sortorder = position*2-1 для строки, чтобы вставить или обновить, или просто удалить любую строку:

update Song
set 
  SortOrder = :NewPosition*2-1
where
  SortOrder = :OldPosition*2;

После этого я просто обновил все строки, чтобы снова исправить нумерацию, независимо от того, где была моя модификация, сгенерировав новую последовательность на основе порядка сортировки.
Это означало бы, что я делал избыточные обновления строк, которые уже были правильными, но это было действительно, действительно легко, все еще очень быстро (потому что базы данных хороши в подобных вещах), и это также имело некоторый эффект автоматического восстановления, потому что Весь список будет перенумерован каждый раз, исправляя ошибки прошлого. Это зависит от вашей базы данных, как именно это реализовать. Я использовал Oracle, который был довольно хорош и генерировал такие последовательности. В MySQL это немного более громоздко, но все же не так сложно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...