按连接列排序,但在另一列上使用distinct

时间:2012-07-07 01:51:43

标签: sql postgresql join

我正在构建一个系统,其中包含以下表格:

  • 广播
  • 按照
  • 用户

用户关注通过广播在其上播放歌曲的电台。

我正在为用户根据他们关注的电台制作歌曲的“馈送”。

以下是查询:

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

sql not working distinct on join

注意:shared_id与id相同。

正如你所看到的,我得到了重复的结果,这是我不想要的。我从previous question发现这是因为在broadcasts.created_at上选择了distinct。

我的问题是:如何修改此查询,以便它只根据其ID 返回唯一的歌曲,但仍然按broadcasts.created_at 排序?

4 个答案:

答案 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)

我在listenstracksalbums之间进行了非常类似的查询,我花了很长时间才弄明白(小时)。

如果您使用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;