SQLite Group By Limit

时间:2013-05-11 22:13:30

标签: sqlite group-by

我有一个生成广播电台播放列表的网络服务,我正在努力确保播放列表中的播放列表永远不会超过 n 次。

所以例如(除非它是Mandatory Metallica --haha),那么任何艺术家都不应该支配任何8小时编程段。

今天我们使用类似于此的查询,从现有的非常大的播放列表中生成较小的随机播放列表:

SELECT FilePath FROM vwPlaylistTracks 
WHERE Owner='{0}' COLLATE NOCASE AND 
Playlist='{1}' COLLATE NOCASE 
ORDER BY RANDOM()
LIMIT {2};

如果相同的艺术家连续出现或超过所需的限制,则有人必须手动查看播放列表并进行一些手动编辑。

假设制作人希望确保在此查询中生成的播放列表范围内没有艺术家出现两次以上(假设vwPlaylistTracks视图中有一个艺术家字段;有)是GROUP BY的正确方法完成这个?

我一直在试图完成此操作,但此查询始终只返回每位艺术家的1首曲目。

SELECT 
   a.Name as 'Artist',
   f.parentPath || '\' || f.fileName as 'FilePath',
   p.name as 'Playlist',
   u.username as 'Owner'
FROM mp3_file f, 
     mp3_track t, 
     mp3_artist a, 
     mp3_playlist_track pt, 
     mp3_playlist p,
     mp3_user u
WHERE f.file_id = t.track_id
AND t.artist_id = a.artist_id
AND t.track_id = pt.track_id
AND pt.playlist_id = p.playlist_id
AND p.user_id = u.user_id
--AND p.Name = 'Alternative Rock'
GROUP BY a.Name
--HAVING Count(a.Name) < 3
--ORDER BY RANDOM()
--LIMIT 50;

1 个答案:

答案 0 :(得分:2)

GROUP BY为分组列中的每个不同值创建一个结果记录,因此这不是您想要的。

您必须使用相同的艺术家计算任何之前的记录,这并不容易,因为随机排序不稳定。 但是,这可以通过临时表来实现,该表由rowid

排序
CREATE TEMPORARY TABLE RandomTracks AS
SELECT a.Name as Artist, parentPath, name, username
FROM ...
WHERE ...
ORDER BY RANDOM();
CREATE INDEX RandomTracks_Artist on RandomTracks(Artist);

SELECT *
FROM RandomTracks AS r1
WHERE -- filter out if there are any two previous records with the same artist
      (SELECT COUNT(*)
       FROM RandomTracks AS r2
       WHERE r2.Artist = r1.Artist
         AND r2.rowid < r1.rowid
      ) < 2
  AND -- filter out if the directly previous record has the same artist
      r1.Artist IS NOT (SELECT Artist
                        FROM RandomTracks AS r3
                        WHERE r3.rowid = r1.rowid - 1)
LIMIT 50;

DROP TABLE RandomTracks;

只需阅读整个播放列表并在代码中对其进行过滤和重新排序,就可能更轻松,更快捷。