2013-05-11 116 views
0

我有一個Web服務可以生成電臺播放列表,我試圖確保播放列表永遠不會有來自同一個藝術家的音軌超過ñ次。因此,例如(除非是Mandatory Metallica --haha),那麼任何藝術家都不應該主宰任何8小時的節目片段。SQLite Group By Limit

今天我們使用類似產生較小的隨機播放列表從現有的非常大的播放列表的查詢:

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; 

回答

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; 

可能更容易和更快地只是讀取整個播放列表和篩選,並在你的代碼重新排序。

+0

謝謝!我會玩這個。我認爲你是對的,在代碼中應用業務規則可能會容易得多。如果解決方案在SQL中更簡單,我不想在代碼中設計複雜的算法,但看起來可能不是。 – 2013-05-13 13:24:31