ruby-on-rails - 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 代码中求和要“慢”或“快”多少。但是,如果您仍想保留一个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
推荐阅读
- sqlite - Node-Red 无法打开 SQLite 数据库
- c# - 使用 Automapper 将 ExpandoObject 字符串属性转换为 DateTime
- python - InvalidArgumentError:矩阵大小不兼容:In[0]:[32,21],In[1]:[128,1]
- python - 在两个表之间绘制箭头(作为图像)(Python)
- typescript - 有人可以告诉我如何禁用由@typescript-eslint/ban-types 触发的所有内容吗?
- javascript - React 是否会阻止用户在登录后查找组件?
- oracle - Oracle LISTAGG 和 Coalesce
- javascript - 为什么传递给函数的对象可以被改变但不能在javascript中重新分配?
- python - 如何为 TO 字段的不同模型创建 ForeignKey 留下机会?
- javascript - 使用 document.getElementsByClassName 更改 css 样式