为什么此AR和查询返回的结果是预期结果的两倍?

时间:2016-12-20 16:18:58

标签: ruby-on-rails activerecord

我从AR查询中得到一个奇怪的结果。使用sum给出的结果是预期结果的两倍。

一些背景

@parent.children.size
=> 1
@parent.children
=> [#<Child id: 1, date: "2016-01-01", quantity: 2>]
@parent.children.group_by_month_of_year(:date).count #using groupdate gem
=> {1=>1, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0, 8=>0, 9=>0, 10=>0, 11=>0, 12=>0}

为什么此总和查询返回1 => 4

@parent.children.group_by_month_of_year(:date).sum(:quantity)
=> {1=>4, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0, 8=>0, 9=>0, 10=>0, 11=>0, 12=>0}

只有1个quantity为2的子记录,查询应该返回1 => 2不应该吗?

我该怎么做呢?

修改

该查询生成以下SQL

SELECT DISTINCT SUM("purchases"."quantity") AS sum_quantity, 
EXTRACT(MONTH from date::timestamptz AT TIME ZONE 'Etc/UTC' - INTERVAL '0 second')::integer 
AS extract_month_from_date_timestamptz_at_time_zone_etc_utc_interv 
FROM "purchases" 
INNER JOIN "people" ON "purchases"."person_id" = "people"."id" 
INNER JOIN "events" ON "people"."id" = "events"."person_id" 
WHERE "events"."location_id" = $1 AND (date IS NOT NULL) 
GROUP BY EXTRACT(MONTH from date::timestamptz AT TIME ZONE 'Etc/UTC'  INTERVAL '0 second')::integer  
[["location_id", 1]]

具有以下关系

class Location
  has_many :events
  has_many :people, -> { distinct }, through: :events
  has_many :purchases, -> { distinct }, through: :people
end

class Event
  belongs_to :location
  belongs_to :person
end

class Person
  has_many :events
  has_many :purchases
end

class Purchase
  belongs_to :person
end

编辑2

在更改关系的定义方式后(如下所示),总和查询正在计算正确的结果。

class Location  
  has_many :events
  has_many :people, -> { distinct }, through: :events
  def purchases
    Purchase.where( person_id: self.people.pluck(:id)
  end 
end

1 个答案:

答案 0 :(得分:0)

当您以这种方式聚合时,在关联中使用distinct是无效的。如果位置和购买之间存在多个连接路径,则distinct将应用于最终聚合结果,而不应用于基础未聚合结果集。

我不确定数据模型是否有效。如果您试图通过个人和事件获得每个地点的销售额,您如何知道购买与特定事件相关联,从而与特定位置相关联?

您不需要直接通过将event_id添加到购买中来将购买链接到此人和活动,或者通过在与购买时间比较的事件上设置时间范围来隐式?

编辑:

在更好地理解你想要做的事情的背景下,这个怎么样......

Purchase.where(person: Person.joins(:events).where(events: {location_id: @location.id}).uniq).
         group_by_month_of_year(:date).sum(:quantity)