Внутреннее соединение Rails Postgres с проблемой агрегатов

#ruby-on-rails #postgresql #inner-join

#ruby-на-рельсах #postgresql #внутреннее соединение #ruby-on-rails

Вопрос:

Такого рода вопросы встречаются повсеместно… но вот в чем моя проблема.

У меня есть модели rails: Organization , Activity , Donation , DonationItem . Я пытаюсь получить суммирование Activity.hours и DonationItem.amount для каждого Organization .

Я не могу использовать прямые отношения (например: Organization.activities.pluck(:hours).sum потому что я нахожусь в ситуации, когда Organization.select("...").group(...) необходимо использовать.

Текущие соединения rails приведены ниже, хотя на данном этапе они явно некорректны:

  @relation = Organization.joins(:activities, donations: :donation_items)
                         .select("organizations.id, sum(activities.hours), sum(donation_items.amount)")
                         .group("organizations.id")
  

Это структура SQL (в основном …) select находится здесь: http://sqlfiddle.com /#!17/fb932e/6

Вот выбор для пользователей, которые не хотят просматривать SQL Fiddle

 select 
        o.id,
        sum(a.hours) as "hours", 
        sum(di.amount) as "amount"
    from organizations o
    inner join activities a 
        on a.organization_id = o.id
    inner join donations d 
        on d.organization_id = o.id
    inner join donation_items di
        on di.donation_id = d.id
    group by o.id
;
  

Я понимаю, в чем проблема, просто не нахожу решения для ее решения…

Будем признательны за любую помощь. Спасибо.

Ответ №1:

В SQL вы можете использовать CTE подпункт or для устранения проблемы с неправильными значениями часов и количества, но не уверен, как бы вы преобразовали их в rails query Builder

Использование CTE

 with organization_activity as (
  select organization_id, sum(hours) as "hours"
  from activities
  group by organization_id 
)
select 
        o.id,
        a.hours as "hours", 
        sum(di.amount) as "amount"
    from organizations o
    inner join organization_activity a 
        on a.organization_id = o.id
    inner join donations d 
        on d.organization_id = o.id
    inner join donation_items di
        on di.donation_id = d.id
    group by o.id, a.hours
;
  

Используя подпункт

 select 
        o.id,
        a.hours as "hours", 
        sum(di.amount) as "amount"
    from organizations o
    inner join (
      select organization_id, sum(hours) as "hours"
      from activities
      group by organization_id
    ) a 
        on a.organization_id = o.id
    inner join donations d 
        on d.organization_id = o.id
    inner join donation_items di
        on di.donation_id = d.id
    group by o.id, a.hours
;
  

ДЕМОНСТРАЦИЯ