0

I'm trying to order a group of TV shows by how many times an actor has been on. I followed some other stack overflow questions asking the same question but I'm getting an error I don't see mentioned anywhere.

 Show.joins(:contributions)
  .select('show.*, COUNT(contributions.id) AS guest_count')
  .where('contributions.role_id = 2')
  .where('contributions.person_id IN (?)', self.id)
  .order('guest_count desc')

PG::SyntaxError: ERROR: syntax error at or near "AS" LINE 1: SELECT COUNT(show.*, COUNT(contributions.id) AS guest_co...

Output:

: SELECT COUNT(COUNT(contributions.id) AS guest_count, show.*) FROM
"show" INNER JOIN "episodes" ON "episodes"."show" = "show"."id" 
INNER JOIN "contributions" ON "contributions"."episode_id" = 
"episodes"."id" WHERE (contributions.role_id = 2) AND 
(contributions.person_id IN (42))

This is the stack overflow I've been following: Rails 3 ActiveRecord: Order by count on association

Community
  • 1
  • 1
Ashbury
  • 2,160
  • 3
  • 27
  • 52

3 Answers3

1

It looks like arel isn't setting up your SQL statement correctly. Try reversing the conditions in the select.

.select('COUNT(contributions.id) AS guest_count, show.*')

Maybe that will help arel out.

EDIT:

You also have a second problem. You're trying to use an aggregate function but you're not indicated which columns you want to group by. When using the aggregate don't use show.* and instead list the columns you want to select. After, use the group method to list the columns so they can be included in the aggregate query.

EDIT 2:

Can you just use something like:

shows = Show.includes(:contributions).all

and access the counts with:

shows.first.contributions.count

or is this a performance issue you're optimizing?

Dane O'Connor
  • 75,180
  • 37
  • 119
  • 173
  • For a show like 'Game of Thrones' I want a table of the most frequent characters listed in order (# of times they've been on, in this case a 'contribution'). – Ashbury Sep 19 '15 at 04:40
  • your tip about reversing the order (putting the COUNT() first) fixed my issue after an upgrade from rails 3.2 – jpw Sep 26 '15 at 18:21
0

The raw SQL could look like this:

SELECT s.*, x.ct
FROM   shows s
LEFT JOIN (
   SELECT e.show, count(*) AS ct
   FROM   episodes e
   JOIN   contributions c ON e.id = c.episode_id
   WHERE  c.role_id = 2
   AND    c.person_id = ?  -- self.id
   GROUP  BY 1
   ) x ON s.id = x.show
ORDER  BY x.ct DESC NULLS LAST;

This includes shows without any appearances of the person, but takes care to sort those last. To exclude those shows use JOIN instead of LEFT JOIN.

Consider:

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
-1

You have to change show tables into shows:

Show.joins(:contributions)
  .select('shows.*, COUNT(contributions.id) AS guest_count')
  .where('contributions.role_id = 2')
  .where('contributions.person_id IN (?)', self.id)
  .group("shows.id")
  .order('guest_count desc')
akbarbin
  • 4,985
  • 1
  • 28
  • 31
  • same error: PG::SyntaxError: ERROR: syntax error at or near "AS" LINE 1: SELECT COUNT(show.*, COUNT(contributions.id) AS guest_co... ^ : SELECT COUNT(show.*, COUNT(contributions.id) AS guest_count) FROM "show" INNER JOIN "episodes" ON "episodes"."show_id" = "show"."id" INNER JOIN "contributions" ON "contributions"."episode_id" = "episodes"."id" WHERE (contributions.role_id = 2) AND (contributions.person_id IN (42)) :( – Ashbury Sep 19 '15 at 05:38
  • Based on your error, you didn't change your `show` into `shows` in your select query. Try it again. :) – akbarbin Sep 19 '15 at 05:41
  • I thought I did. I just tried again after restarting and I'm getting a different error :) PG::GroupingError: ERROR: column "shows.id" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT shows.*, COUNT(contributions.id) AS guest_count FR... ^ : SELECT shows.*, COUNT(contributions.id) AS guest_count FROM "shows" INNER JOIN "episodes" ON "episodes"."show_id" = "shows"."id" INNER JOIN "contributions" ON "contributions"."episode_id" = "episodes"."id" WHERE (contributions.role_id = 2) AND (contributions.person_id IN (42)) ORDER BY guest_count desc – Ashbury Sep 19 '15 at 08:14
  • It's okay. I thought, Postgres needs `group_by` to count your guest_count. I will update it later. – akbarbin Sep 19 '15 at 13:15