1

次のテーブルがあるシステムを構築しています。

  • ブロードキャスト
  • 従う
  • ユーザー

ユーザーは、放送を通じて曲が放送されているステーションをフォローします。

私は、ユーザーがフォローしているステーションに基づいて、ユーザー向けの曲の「フィード」を作成しています。

クエリは次のとおりです。

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が結合時に明確に機能しない

注:shared_idはidと同じです。

ご覧のとおり、重複した結果が得られていますが、これは望ましくありません。以前の質問から、これはbroadcasts.created_atで個別に選択したことが原因であることがわかりました。

私の質問は次のとおりです。このクエリを変更して、IDに基づいて一意の曲のみを返し、broadcasts.created_atで並べ替えるにはどうすればよいですか。

4

4 に答える 4

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に含める必要があります。ステーションに関係なく、一意の最大日付のみが必要です。

次に、その結​​果をテーブルへの外部クエリにsongs結合して、それぞれの一意に関連付けられた曲情報を取得しますsong_id

于 2012-07-07T02:35:41.803 に答える
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を構築できます。

于 2012-07-07T02:57:04.683 に答える
0

追加してみてくださいGROUP BY Songs.id

于 2012-07-07T02:01:27.783 に答える
0

との間listensで行っていたクエリと非常によく似ていて、それを理解するのに長い時間がかかりました(時間)。tracksalbums

を使用する場合は、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;
于 2014-07-06T11:17:00.097 に答える