首页 > 解决方案 > 通过 Rails 和 Postgresql 中对象的属性总和限制查询

问题描述

我有一个 Lead 模型,它有一个名为“sms_price”的预先计算的浮点列。我希望允许用户向这些潜在客户发送短信,并为他们的活动分配预算(类似于您在 fb 广告上可以找到的内容)。

我需要一个可以通过这些潜在客户的总价格限制潜在客户数量的范围。例如,如果用户定义了 200 的总预算

所以我需要在我的范围内做两件事:

  1. 递归计算总价
  2. 仅获取总价低于所需预算的潜在客户

到目前为止,我只设法使用此范围完成了第一项任务(递归计算总价):

scope :limit_by_total_price, ->{select('"leads".*, sum(sms_price) OVER(ORDER BY id) AS total_price')}

这有效,如果我这样做,Lead.limit_by_total_price.last.total_price我会得到38039.7499999615

现在我需要的是一种仅检索总价低于预算的潜在客户的方法:

scope :limit_by_total_price, ->(budget){select('"leads".*, sum(sms_price) OVER(ORDER BY id) AS total_price').where('total_price < ?', budget)}

但它不识别 total_price 属性:

ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column "total_price" does not exist

为什么它识别单个对象中的 total_price 属性而不是范围?

标签: ruby-on-railspostgresqlactiverecordruby-on-rails-5

解决方案


问题是在 SELECT 子句中计算的列不可用于同一语句中的 WHERE 子句。为了做你想做的事,你需要一个子查询。

from您可以使用 ActiveRecord 的方法执行此操作,但仍留在 Rails 世界中。此 Hashrocket 博客文章很好地说明了该技术。

在您的情况下,它可能看起来像这样(由于复杂性,我将使用类方法而不是范围):

def self.limit_by_total_price(budget)
  subquery = select('leads.*, sum(leads.sms_price) over(order by leads.id) as total_price')
  from(subquery, :leads).where('total_price < ?', budget)
end

推荐阅读