轨道查找具有两个具有特定属性的子项的父级



我的数据库中有超过 100,000 个不同产品的对象。每个产品有4-6个变体。因此,通过遍历所有内容来懒惰地编辑大量数据并不容易。因此,我试图只获得我需要的确切数量的产品。

到目前为止,我可以获得所有具有尺寸属性为"SM"的变体的产品。

挂断电话,是获取所有同时具有尺寸为"MD"和"SM"的变体的产品。

这是我正在使用的代码Product.joins(:variants).where('variants.size = ?', 'SM')

我尝试向其添加.where('variants.size = ?', 'MD'),但这确实有效。

这个怎么样

Product.where(
id: Variant.select(:product_id)
.where(size: 'SM')
).where(id: Variant.select(:product_id)
.where(size: 'MD')
)

这应该生成类似于

SELECT products.* 
FROM products 
WHERE products.id IN (SELECT 
variants.product_id 
FROM variants 
WHERE size = 'SM') 
AND products.id IN (SELECT 
variants.product_id 
FROM variants 
WHERE size = 'MD') 

因此,产品 ID 必须同时位于两个列表中才能选择。

此外,这也应该有效(不是 100% 确定(

Product.where(id: Product.joins(:variants)
.where(variants: {size: ['SM', 'MD']})
.group(:id)
.having('COUNT(*) = 2').select(:id)

这应该产生类似的东西

SELECT products.*
FROM products
WHERE 
products.id IN ( SELECT products.id
FROM products
INNER JOIN variants 
ON variants.product_id = products.id
WHERE 
variants.size IN ('SM','MD')
GROUP BY 
products.id
HAVING 
Count(*) = 2  

另一个选择

p_table = Products.arel_table
v_table = Variant.arel_table
sm_table = p_table.join(v_table)
.on(v_table[:product_id].eq(p_table.[:id])
.and(v_table[:size].eq('SM'))
)
md_table = p_table.join(v_table)
.on(v_table[:product_id].eq(p_table.[:id])
.and(v_table[:size].eq('MD'))
)
Product.joins(sm_table.join_sources).joins(md_table.join_sources)

.SQL

SELECT products.*
FROM products
INNER JOIN variants on variants.product_id = products.id
AND variants.size = 'SM'
INNER JOIN variants on variants.product_id = products.id
AND variants.size = 'MD'

这 2 个联接应强制中小型

联接,因为 内部联接

恕我直言,你需要使用更多的SQL而不是Rails魔法来构建这样的数据库查询。

Product
.joins('INNER JOIN variants as sm_vs ON sm_vs.product_id = products.id')
.joins('INNER JOIN variants as md_vs ON md_vs.product_id = products.id')
.where(sm_vs: { size: 'SM' })
.where(md_vs: { size: 'MD' })

或简化 - 如@engineersmnky建议:

Product
.joins("INNER JOIN variants as sm_vs ON sm_vs.product_id = products.id AND sm_vs.size = 'SM'")
.joins("INNER JOIN variants as md_vs ON md_vs.product_id = products.id AND sm_vs.size = 'MD'")

两个查询执行基本相同的操作。只需选择您更喜欢的版本。

Product.joins(:variants(.where('variants.size = ?OR 变体.size = ?', 'SM','MD'(

最新更新