我有这个ruby代码导致postgresql引发column "urls.id" must appear in the GROUP BY
。
Song.
joins(:artist).
references(:artist).
where("artists.active = ?", true).
group("songs.id").
includes(:urls)
问题是在添加includes(:urls)
而不是运行单独的查询时,rails正在加入。是否可以强制rails运行第二个查询以避免此问题?
换句话说;我希望rails在使用JOIN
时使用SQL ActiveRecord::Relation.joins
,在使用ActiveRecord::Relation.includes
时使用单独的查询。
删除where
和references
方法会使所有内容都通过,但我无法查询艺术家表。
错误消息。
SELECT "songs"."id" AS t0_r0, "songs"."artist_id" AS t0_r1, "songs"."title" AS t0_r2, "songs"."grade" AS t0_r3, "songs"."length" AS t0_r4, "songs"."gigs_count" AS t0_r5, "songs"."clicks" AS t0_r6, "songs"."album_cover_id" AS t0_r7, "songs"."created_at" AS t0_r8, "songs"."updated_at" AS t0_r9, "songs"."position" AS t0_r10, "songs"."services" AS t0_r11, "songs"."moved_id" AS t0_r12, "songs"."details_updated_at" AS t0_r13, "songs"."genres_updated_at" AS t0_r14, "urls"."id" AS t1_r0, "urls"."url" AS t1_r1, "urls"."service_id" AS t1_r2, "urls"."media_id" AS t1_r3, "urls"."media_type" AS t1_r4, "urls"."extra" AS t1_r5 FROM "songs" INNER JOIN "artists" ON "artists"."id" = "songs"."artist_id" LEFT OUTER JOIN "url_bridges" ON "url_bridges"."media_bridge_id" = "songs"."id" AND "url_bridges"."media_bridge_type" = 'Song' LEFT OUTER JOIN "urls" ON "urls"."id" = "url_bridges"."url_id" WHERE (artists.active = 't') AND "songs"."id" IN (944) GROUP BY songs.id
PG::GroupingError: ERROR: column "urls.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ...AS t0_r13, "songs"."genres_updated_at" AS t0_r14, "urls"."id...
^
: SELECT "songs"."id" AS t0_r0, "songs"."artist_id" AS t0_r1, "songs"."title" AS t0_r2, "songs"."grade" AS t0_r3, "songs"."length" AS t0_r4, "songs"."gigs_count" AS t0_r5, "songs"."clicks" AS t0_r6, "songs"."album_cover_id" AS t0_r7, "songs"."created_at" AS t0_r8, "songs"."updated_at" AS t0_r9, "songs"."position" AS t0_r10, "songs"."services" AS t0_r11, "songs"."moved_id" AS t0_r12, "songs"."details_updated_at" AS t0_r13, "songs"."genres_updated_at" AS t0_r14, "urls"."id" AS t1_r0, "urls"."url" AS t1_r1, "urls"."service_id" AS t1_r2, "urls"."media_id" AS t1_r3, "urls"."media_type" AS t1_r4, "urls"."extra" AS t1_r5 FROM "songs" INNER JOIN "artists" ON "artists"."id" = "songs"."artist_id" LEFT OUTER JOIN "url_bridges" ON "url_bridges"."media_bridge_id" = "songs"."id" AND "url_bridges"."media_bridge_type" = 'Song' LEFT OUTER JOIN "urls" ON "urls"."id" = "url_bridges"."url_id" WHERE (artists.active = 't') AND "songs"."id" IN (944) GROUP BY songs.id
我在x86_64-unknown-linux-gnu上运行PostgreSQL 9.3.2,由gcc-4.4.real(Ubuntu 4.4.3-4ubuntu5)4.4.3,64位编译。
答案 0 :(得分:5)
将includes
替换为preload
,文档内容不够明确,但会运行第二个查询以急切加载您指定的关系。我已将其用于与joins
和group
相同的用例。
Song.
joins(:artist).
references(:artist).
where("artists.active = ?", true).
group("songs.id").
preload(:urls)
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-preload
答案 1 :(得分:0)
我建议手动第二次查询网址。不要使用包含(:urls)。
@songs = Song.complex_query
@urls = Url.where(:song_id => @songs.ids)
@urls_by_song_id = @urls.group_by {|u| u.song_id}
使用group_by会将url放入哈希,其中键为song_id,值为url数组。您可以访问这样的网址:
@urls_by_song_id[song.id]
它不像包含一样干净,但它具有相同的效果。这使您可以访问没有n + 1开销的URL。