我正在构建一个系统,其中包含以下表格:
用户关注通过广播在其上播放歌曲的电台。
我正在为用户根据他们关注的电台制作歌曲的“馈送”。
以下是查询:
SELECT DISTINCT ON ("broadcasts"."created_at", "songs"."id") songs.*
FROM "songs"
INNER JOIN "broadcasts" ON "songs"."shared_id" = "broadcasts"."song_id"
INNER JOIN "stations" ON "broadcasts"."station_id" = "stations"."id"
INNER JOIN "follows" ON "stations"."id" = "follows"."station_id"
WHERE "follows"."user_id" = 2
ORDER BY broadcasts.created_at desc
LIMIT 18
注意:shared_id与id相同。
正如你所看到的,我得到了重复的结果,这是我不想要的。我从previous question发现这是因为在broadcasts.created_at上选择了distinct。
我的问题是:如何修改此查询,以便它只根据其ID 返回唯一的歌曲,但仍然按broadcasts.created_at 排序?
答案 0 :(得分:2)
试试这个解决方案:
SELECT a.maxcreated, b.*
FROM
(
SELECT bb.song_id, MAX(bb.created_at) AS maxcreated
FROM follows aa
INNER JOIN broadcasts bb ON aa.station_id = bb.station_id
WHERE aa.user_id = 2
GROUP BY bb.song_id
) a
INNER JOIN songs b ON a.song_id = b.id
ORDER BY a.maxcreated DESC
LIMIT 18
FROM
子选择检索用户遵循的所有电台广播的不同song_id
;它还获得与每首歌曲相关的最新广播日期。我们必须在子查询中包含它,因为我们必须在我们选择的列上GROUP BY
,并且我们只需要唯一的song_id
和maxdate,而不管站点。
然后我们将结果加入到songs
表的外部查询中,以获取与每个唯一song_id
相关联的歌曲信息
答案 1 :(得分:2)
如果您想要更清晰的查询,可以使用Common Table Expressions (CTE)(嵌套查询会让事情变得更难阅读)
我看起来像这样:
WITH a as (
SELECT bb.song_id, MAX(bb.created_at) AS maxcreated
FROM follows aa
INNER JOIN broadcasts bb ON aa.station_id = bb.station_id
INNER JOIN songs cc ON bb.song_id = cc.shared_id
WHERE aa.user_id = 2
GROUP BY bb.song_id
)
SELECT
a.maxcreated,
b.*
FROM a INNER JOIN
songs b ON a.song_id = b.id
ORDER BY
a.maxcreated DESC
LIMIT 18
使用CTE具有提高可读性和易于维护复杂查询的优点。查询可以分为单独的简单逻辑构建块。然后,可以使用这些简单的块来构建更复杂的临时CTE,直到生成最终结果集。
答案 2 :(得分:0)
尝试添加GROUP BY Songs.id
答案 3 :(得分:0)
我在listens
,tracks
和albums
之间进行了非常类似的查询,我花了很长时间才弄明白(小时)。
如果您使用GROUP_BY songs.id
,则可以通过MAX(broadcasts.created_at) DESC
订购来使其发挥作用。
这是完整SQL的样子:
SELECT songs.* FROM "songs"
INNER JOIN "broadcasts" ON "songs"."shared_id" = "broadcasts"."song_id"
INNER JOIN "stations" ON "broadcasts"."station_id" = "stations"."id"
INNER JOIN "follows" ON "stations"."id" = "follows"."station_id"
WHERE "follows"."user_id" = 2
GROUP BY songs.id
ORDER BY MAX(broadcasts.created_at) desc
LIMIT 18;