Столбец Rails PG GroupingError должен появиться в предложении GROUP BY.

есть несколько тем об этом уже с принятыми ответами, но я не смог найти решение, основанное на них: например:

Мой запрос:

Idea.unscoped.joins('inner join likes on ideas.id = likes.likeable_id').
select('likes.id, COUNT(*) AS like_count, ideas.id, ideas.title, ideas.intro, likeable_id').
group('likeable_id').
order('like_count DESC')

Это хорошо при разработке с sqlite, но ломается на героку с PostgreSQL.

Ошибка:

PG::GroupingError: ERROR:  column "likes.id" must appear in the GROUP BY clause or be used in an aggregate function

Если я поставлю likes.id в свою группу к тому времени, результаты не будут иметь смысла. Пробовал ставить группу перед select, но не помогает. Я даже попытался разделить запрос на две части. Нет радости. :(

Любые предложения приветствуются. ТИА!


person Zsolt    schedule 19.02.2015    source источник


Ответы (1)


Я не знаю, почему вы хотите выбрать likes.id в первую очередь. Я вижу, что вы в основном хотите like_count для каждой идеи; Не вижу смысла выбирать likes.id. Кроме того, когда у вас уже есть ideas.id, я не понимаю, почему вы хотите получить значение likes.likeable_id, поскольку они оба будут равны. :/

В любом случае, проблема в том, что, поскольку вы группируете по likeable_id (в основном ideas.id), вы не можете «выбрать» likes.id, так как они будут «потеряны» при группировке.

Я полагаю, что SQLite слабо относится к этому. Я предполагаю, что это не сгруппирует вещи должным образом.

В ЛЮБОМ СЛУЧАЕ(2) =>

Позвольте мне предложить более чистое решение.

# model
class Idea < ActiveRecord::Base
  # to save you the effort of specifying the join-conditions
  has_many :likes, foreign_key: :likeable_id
end

# in your code elsewhere
ideas = \
  Idea.
  joins(:likes).
  group("ideas.id").
  select("COUNT(likes.id) AS like_count, ideas.id, ideas.title, ideas.intro").
  order("like_count DESC")

Если вы все же хотите получить идентификаторы лайков для каждого элемента, то после вышеизложенного вы можете сделать следующее:

grouped_like_ids = \
  Like.
  select(:id, :likeable_id).
  each_with_object({}) do |like, hash|
    (hash[like.likeable_id] ||= []) << like.id
  end

ideas.each do |idea|
  # selected previously:
  idea.like_count
  idea.id
  idea.title
  idea.intro

  # from the hash
  like_ids = grouped_like_ids[idea.id] || []
end

Другие читатели: Меня бы очень заинтересовало «чистое» решение с одним запросом без подзапросов. Дайте мне знать в комментариях, если вы оставите ответ. Спасибо.

person SHS    schedule 19.02.2015
comment
Ух ты! Спасибо, это было быстро! Забыл добавить, что я только начал веб-разработку 1,5 месяца назад. - person Zsolt; 19.02.2015
comment
array_agg() может объединять каждый отдельный идентификатор в массив (я думаю, ruby поддерживает массивы PostgreSQL, но я не уверен) -- в любом случае можно использовать string_agg(), если массивы не поддерживаются в RoR - person pozs; 19.02.2015
comment
@pozs, обратите внимание, что нам нужно решение, которое будет работать и в SQLite. OP использует SQLite в разработке. - person SHS; 19.02.2015
comment
@Humza, да, если для обработки обоих поставщиков требуется один запрос, это не поможет. Но string_agg() работает так же, как group_concat() SQLite, если OP приемлем изменяющийся запрос. - person pozs; 19.02.2015
comment
Я не знаю человека. Rails.env.production? ? postgres_function : (Rails.env.development? ? sqlite_function : something_else) выглядит очень грязно. Спасибо за вклад, хотя. - person SHS; 19.02.2015