首页 > 解决方案 > Rails (Activerecord) - 无法使用连接和全局总和进行查询而不重复

问题描述

我正在使用具有多个用户设置过滤器的查询,以便在 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)

我的问题是,考虑到我需要双重连接才能通过项目访问估算,并且每个发票都属于一个项目,但是一个项目可以有很多估算,连接操作会导致重复记录,所以我的 Invoices 表多次显示某些发票(与其项目的估算数量一样多)。这会导致发票表中包含重复记录,并且总和值不正确,因为它对某些发票总计进行了 N 次求和。

过滤行为很好,因为我的意图是按在发票项目中进行任何估计的用户进行过滤。然而,问题是当我试图通过添加一个组('invoices.id')来避免重复时 - 我总是解决这种情况的方式 - 最终的求和操作不会返回发票总和的总和,而是它们中的每一个的分组总和(完全没用)。

我发现的唯一解决方法是包含 group 子句并在纯 ruby​​ 代码中执行求和,将集合视为一个数组,恕我直言,这是非常低效的,因为有大量的发票:

@invoices.map(&:total_cache).inject(0, &:+)

有没有一种方法可以获得唯一的 ActiveRecord 发票集合而没有重复,然后我可以调用聚合总和方法并获得由 Postgres 计算的总数?

当然,如果我的基本想法有问题,我完全愿意听到它!这是一个相当复杂的查询(为了这里的问题,我对其进行了简化),我敢肯定有很多方法!

谢谢大家!

标签: ruby-on-railspostgresqlactiverecord

解决方案


我不确定这比在 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

推荐阅读