为了在 Rails 应用程序中显示发票列表,我正在使用具有多个用户设置过滤器的查询。其中一个过滤器在单独表的列上添加了一个 where 条件,该表需要双连接才能访问(估计 - 通过项目 -)。
scope :by_seller, lambda {|user_id|
joins(project: :estimates)
.where(estimates: {:user_id => user_id}) unless user_id.blank?
}
此外,我使用 Rails 的聚合方法“sum”来找出发票的总额,@invoices.sum(:total_cache),其中 total_cache 是数据库中专门用于执行此类操作的缓存列以高效的方式求和。
@invoices.sum(:total_cache)
我的问题是,考虑到我需要双连接才能通过项目访问估算,并且每个发票都属于一个项目,但一个项目可以有很多估算,连接操作会导致重复记录,所以我的发票表多次显示某些发票(与其项目的估算数量一样多)。这会导致发票表中有重复的记录,并且总和值不正确,因为它将某些发票总额相加 N 次。
过滤行为很好,因为我的目的是按在发票项目中进行任何估算的用户进行过滤。然而,问题是当我试图通过添加一个组('invoices.id')来避免重复时 - 我总是解决这种情况的方式 - 最终的总和操作不会返回发票总额的总和,而是每一个的总和(完全没用)。
我发现的唯一解决方法是包含 group 子句并在纯 ruby 代码中执行求和,将集合视为数组,恕我直言,这是非常低效的,因为有大量发票:
@invoices.map(&:total_cache).inject(0, &:+)
有没有一种方法可以获得唯一的 ActiveRecord 发票集合而不重复,然后我可以调用聚合求和方法并获得由 Postgres 计算的总数?
当然,如果我的基本想法有什么问题,我完全愿意听取意见!这是一个相当复杂的查询(为了这里的问题我简化了它)而且我相信可以有很多方法!
谢谢大家!
最佳答案
我不确定这比用 ruby 代码求和“慢”或“快”多少。但是,如果您仍想保留一个 ActiveRecord::Relation
对象,那么您可以执行如下操作。我在本地 Rails 项目中复制了您的设置环境。
user = User.first
Invoice.where(
id: Invoice.by_seller(user.id).select(:id)
).sum(:total_cache)
# (1.2 ms) SELECT SUM("invoices"."total_cache") FROM "invoices" WHERE "invoices"."id" IN (SELECT "invoices"."id" FROM "invoices" INNER JOIN "projects" ON "projects"."id" = "invoices"."project_id" INNER JOIN "estimates" ON "estimates"."project_id" = "projects"."id" WHERE "estimates"."user_id" = $1) [["user_id", 1]]
# => 5
关于ruby-on-rails - Rails (Activerecord) - 无法使用没有重复的连接和全局总和进行查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54461827/