2017-07-07 80 views
0

Alrigth,所以我不知道這是不是太具體...但我真的不知道如何構建這樣的查詢,既不在AR,也不在SQL中。所以這裏的情況:ActiveRecord:一種複雜的查詢嵌套關聯和排序

  • 我有一個User模型。 User has_many Project s。一個Project,反過來,有下列協會:
  • Project HAS_ONE BasicEvent
  • Project had_many AdditionalEvent小號
  • BasicEventAdditionalEvent類是建立在從AR模型類的繼承,Event

現在,目標是:在我看來,我需要:

  • 訪問所有Project count:伯爵每User
  • 訪問所有Event count:伯爵,其中happened_at屬性在nil
  • 已全部User小號排序,由Event S上的計數,其中happened_at屬性在nil

到目前爲止,我做了一些嘗試,但沒有真正得到太多......我將不勝感激任何有關這種複雜(至少從我的角度來看)的查詢的幫助。

+0

你能更具體說明你想要什麼嗎?我有點困惑你的計數每個用戶和其他 –

+0

不確定,但我會嘗試。我想知道'用戶'具有的項目數量。並且還計算每個User的'Event's(但是這兩者之間沒有直接關聯,它通過'Project'發生)。最後,我希望所有'用戶'按「事件」的次數排序。我希望有所幫助。 –

+0

是否有項目和事件之間的任何關聯?並且應該有用戶關聯到有許多事件的徹底項目。源將是事件 –

回答

0

您可以從代碼開始,如:

# -*- frozen-string-literal: true -*- 
class UserStatService 
    SELECT_CLAUSE = <<~SQL 
    (SELECT count(1) FROM projects WHERE user_id=users.id) AS projects_count, 
    (SELECT count(1) FROM events WHERE (happened_at IS NULL) 
     AND (project_id IN (SELECT id FROM projects WHERE user_id=users.id) 
    ) AS events_count, 
    users.* 
    SQL 

    def call 
    User 
     .select(SELECT_CLAUSE) 
     .order('events_count') 
    end 
end 

在ResultSet中的每個User實例將有projects_countevents_count屬性。

還推薦任何類型的緩存(counter_cache或手工製作)。因爲查詢預計不會很快。

0

假設basic_eventsadditional_events具有基本相同的列,極大地解決了這個問題,將改變你的數據庫/應用程序使用single table inheritance

假設你正在使用Rails低於5.x您的模型應該是這樣的:

class User < ApplicationRecord 
    has_many :projects 
    has_many :basic_events, through: :projects 
    has_many :additional_events, through: :projects 
end 
class Project < ApplicationRecord 
    belongs_to :user 
    has_one :basic_event 
    has_many :additional_events 
end 
class Event < ApplicationRecord 
    belongs_to :project 
end 
class BasicEvent < Event 
    belongs_to :project 
end 
class AdditionalEvent < Event 
    belongs_to :project 
end 

這樣,只有三個表涉及users,projectsevents。您的events表格將有一個:type列,您可以在其中指定它是否爲basicadditional


對於您的疑問:

訪問所有項目每用戶

User 
    .select("users.*, count(projects.id) AS projects_count") 
    .joins(:projects) 
    .group('users.id') 
    .order('projects_count DESC') 

計數使用select這樣給你訪問一個:projects_count方法上的每個用戶對象返回這個活躍的記錄關係,所以如果你將這個查詢分配給一個名爲users_with_projects_count的變量,你可以做users_with_projects_count.first.projects_count它會ret與該用戶關聯的項目數量。

訪問所有活動計數,在零

User 
    .select("users.*, count(events.id) AS events_count") 
    .joins(:events) 
    .where('events.happened_at IS NULL') 
    .group('users.id') 

其中happened_at屬性,您可以訪問:events_count你在過去的例子一樣:projects_count的方式相同。

已去所有用戶進行排序,事件的計數,其中happened_at屬性在零

User 
    .select("users.*, count(events.id) AS events_count") 
    .joins(:events) 
    .where('events.happened_at IS NULL') 
    .group('users.id') 
    .order('events_count DESC') 

可以使用相同的查詢作爲最後一個例子只需要加一個:order

0

項目計算每個用戶:Project.group(:user_id).count

活動計數,其中happened_at屬性在nilEvent.where(happened_at: nil).count

用戶分類,事件的計數,其中在nilhappened_at屬性:這是最棘手的,但它也並不是特別困難:

User. 
    select("users.*, (SELECT COUNT(*) FROM events WHERE user_id = users.id AND happened_at IS NULL) AS unhappened_events_count"). 
    order("unhappened_events_count DESC") 

這不是一個特別有效的查詢,但它應該做的Ĵ對於數千條記錄(很容易)很好 - 特別是如果您在events表中設置了user_idhappened_at的索引。