2014-12-11 40 views
0

我想通過created_at命令,然後根據外鍵獲取一個DISTINCT集。ORDER BY和DISTINCT ON(...)在Rails中

另一部分是以某種方式使用這是ActiveModelSerializer。具體來說,我希望能夠宣佈:

has_many :somethings

在串行器。讓我進一步解釋...

我能夠得到我需要這個自定義SQL的結果:

def latest_product_levels 
    sql = "SELECT DISTINCT ON (product_id) client_product_levels.product_id,  
    client_product_levels.* FROM client_product_levels WHERE client_product_levels.client_id = #{id} ORDER BY product_id, 
    client_product_levels.created_at DESC"; 
    results = ActiveRecord::Base.connection.execute(sql) 
end 

是否有任何可能的方式來得到這個結果,但作爲一個的has_many關係的條件那麼我可以在AMS中使用它?

在僞代碼:@client.order(created_at: :desc).select(:product_id).distinct

那當然失敗了,超出我的原因:@ client.products_levels像 會做一些。

任何幫助將是偉大的。

謝謝。

回答

3

構建這個結構的一個好方法是將查詢分爲兩部分:第一部分管理行的過濾,以便只獲取最新的客戶端產品級別。第二部分使用標準has_many關聯連接ClientClientProductLevel

ClientProductLevel模型開始,您可以創建一個作用域做最新的過濾:

class ClientProductLevel < ActiveRecord::Base 
    scope :latest, -> { 
    select("distinct on(product_id) client_product_levels.product_id, 
            client_product_levels.*"). 
    order("product_id, created_at desc") 
    } 
end 

你可以在任何地方,你有一個返回ClientProductLevel對象列表查詢中使用此範圍內,例如,ClientProductLevel.latestClientProductLevel.where("created_at < ?", 1.week.ago).latest

如果您還沒有這樣做的話,請設置您Client類與has_many關係:

class Client < ActiveRecord::Base 
    has_many :client_product_levels 
end 

然後在你的ActiveModelSerializer試試這個:

class ClientSerializer < ActiveModel::Serializer 
    has_many :client_product_levels 

    def client_product_levels 
    object.client_product_levels.latest 
    end 
end 

當調用ClientSerializer序列化對象Client,串行看到has_many聲明,它通常會期待您的Client對象,但由於我們通過該名稱獲得了本地定義的方法,而是調用該方法。 (請注意,這個has_many聲明與ActiveRecord has_many不一樣,它指定了表之間的關係:在這種情況下,它只是說串行器應該在關鍵字'client_product_levels'下提供一個序列化對象的數組。)

ClientSerializer#client_product_levels方法依次從客戶端對象調用has_many關聯,然後將latest作用域應用於它。 ActiveRecord最強大的功能就是它可以讓你將不同的組件鏈接到一個查詢中。這裏,has_many生成`where client_id = $ X'部分,範圍生成查詢的其餘部分。 Et瞧!

在簡化方面:ActiveRecord沒有對distinct on的原生支持,所以你堅持使用自定義sql的那部分。我不知道您是否需要在您的select子句中明確包含client_product_levels.product_id,因爲它已包含在*中。你可以嘗試傾銷它。

+0

謝謝!這工作。我知道這裏有一個小題目,但你介意解釋這是如何工作的嗎?查看ClientProductLevel上的sql看起來像只會返回全局最新的。我看到了實際得到的sql:'SELECT distinct on(product_id)client_product_levels.product_id, client_product_levels。​​ FROM「client_product_levels」WHERE「client_product_levels」。「client_id」= $ 1 ORDER BY product_id,created_at desc [[「client_id」, 312]]'。只是想了解如何在範圍和has_many – 2014-12-11 16:55:03

+0

之間創建此外,有沒有辦法建立這個查詢沒有自定義SQL? – 2014-12-11 16:57:30

+0

不客氣!很高興它的工作。我會在上面的答案中提供更多的解釋。 ActiveRecord,AFAIK不支持Postgres'distinct on'機制,並且使用僅由AR本地支持的功能來構建查詢的替代方式是一團糟。 – 2014-12-11 22:08:16