簡體   English   中英

如何使用單個SQL查詢從activerecord有效地檢索對象組?

[英]How to efficiently retrieve groups of objects from activerecord with a single SQL query?

我有一個表products ,上面有一個product_type_code列。 我想做的是根據此列檢索不同數量的對象(例如:3個product_type_code = 'fridge'產品,6個product_type_code = 'car'產品,9個product_type_code = 'house' ,等等。 )。

我知道我可以這樣:

fridges = Product.where(product_type_code: 'fridge').limit(3)
houses = Product.where(product_type_code: 'house').limit(9)
[...]

甚至創建這樣的范圍:

# app/models/product.rb

scope :by_product_type_code, -> (material) { where(product_type_code: product_type_code) }

但是,這效率不高,因為如果我沒記錯的話,我將數據庫訪問了3次。 我想做的是這樣的:

scope :by_product_type_code, -> (hash) { some_method(hash) }

哈希為: { fridge: 3, car: 6, house: 9 }

並獲得一個ActiveRecord_Relation,其中包含3台冰箱,6輛汽車和9座房屋。

我如何有效地做到這一點?

您可以使用UNION ALL創建查詢,該查詢選擇具有特定product_type_code記錄,並limit將其與find_by_sql一起使用:

{ fridge: 3, car: 6, house: 9 }.map do |product_type_code, limit|
  "(SELECT *
   FROM products
   WHERE product_type_code = '#{product_type_code}'
   LIMIT #{limit})"
end.join(' UNION ALL ')

您將有一個類似的查詢:

(SELECT * FROM products WHERE product_type_code = 'fridge'LIMIT 3)
UNION ALL
(SELECT * FROM products WHERE product_type_code = 'car'LIMIT 6)
UNION ALL
(SELECT * FROM products WHERE product_type_code = 'house'LIMIT 9)

@SebastianPalma的答案是最好的解決方案; 但是,如果您正在尋找一種生成該查詢的更“卑鄙”的方式,則可以如下使用arel

scope :by_product_type_code, ->(h) { 
   products_table = self.arel_table
   query = h.map do |product_type,limit| 
     products_table.project(:id)
       .where(products_table[:product_type_code].eq(product_type))
       .take(limit)
   end.reduce do |scope1, scope2|
     Arel::Nodes::UnionAll.new(scope1,scope2)
   end 
   self.where(id: query)
end

這將導致子查詢成為where子句的一部分。

要么

scope :by_product_type_code, ->(h) { 
   products_table = self.arel_table
   query = h.map do |product_type,limit| 
     products_table.project(Arel.star)
       .where(products_table[:product_type_code].eq(product_type))
       .take(limit)
   end.reduce do |scope1, scope2|
     Arel::Nodes::UnionAll.new(scope1,scope2)
   end 
   sub_query = Arel::Nodes::As.new(query,products_table)
   self.from(sub_query)
end 

這將導致子查詢成為數據源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM