Ruby on rails ActiveRecord查询以查找过去3个月内未进行购买的所有用户

Ruby on rails ActiveRecord查询以查找过去3个月内未进行购买的所有用户,ruby-on-rails,ruby-on-rails-3,activerecord,arel,Ruby On Rails,Ruby On Rails 3,Activerecord,Arel,我有一个具有关联购物车的用户模型。每个购物车都有一个“在日期时购买”列。 我想选择过去3个月内没有购买购物车的所有用户 我想一个简单的例子: User.joins(:carts).where('not carts.purchased_at < ?', 3.months.ago) 这会起作用,但事实似乎并非如此。我被退回过去3个月内购买过东西的用户记录 有什么想法吗?我建议您使用原始SQL User.find_by_sql(' SELECT users.* FROM users WHE

我有一个具有关联购物车的用户模型。每个购物车都有一个“在日期时购买”列。 我想选择过去3个月内没有购买购物车的所有用户

我想一个简单的例子:

User.joins(:carts).where('not carts.purchased_at < ?', 3.months.ago)
这会起作用,但事实似乎并非如此。我被退回过去3个月内购买过东西的用户记录


有什么想法吗?

我建议您使用原始SQL

User.find_by_sql('
  SELECT users.* FROM users WHERE id NOT IN 
  (SELECT users.id FROM users LEFT JOIN carts ON users.id = carts.user_id
  WHERE carts.purchased_at < ?)
', 3.months.ago)

记住,这只是一个建议。我认为代码需要一些重构,但你已经想到了。

我建议你使用原始SQL

User.find_by_sql('
  SELECT users.* FROM users WHERE id NOT IN 
  (SELECT users.id FROM users LEFT JOIN carts ON users.id = carts.user_id
  WHERE carts.purchased_at < ?)
', 3.months.ago)
记住,这只是一个建议。我认为代码需要一些重构,但你已经有了主意。

使用gem进行如此复杂的查询:

User.where{id.not_in User.joins{carts}.where{carts.purchased_at > 3.months.ago}}
使用gem进行此类复杂查询:

User.where{id.not_in User.joins{carts}.where{carts.purchased_at > 3.months.ago}}

如果您正在使用AR3和ARel:

User.joins(:carts).where(Cart.arel_table[:purchased_at].gt(3.months.ago))

如果您正在使用AR3和ARel:

User.joins(:carts).where(Cart.arel_table[:purchased_at].gt(3.months.ago))

您应该能够在普通活动记录中执行此操作:

User.joins(:carts)
  .group("users.id")
  .having("MAX(carts.purchased_at) < ?", 3.months.ago)

您应该能够在普通活动记录中执行此操作:

User.joins(:carts)
  .group("users.id")
  .having("MAX(carts.purchased_at) < ?", 3.months.ago)
如果你有一个巨大的购物车,使用MAX和GroupBy可能会很慢。我会使用这种方法

nq = Cart.where("carts.user_id = users.id AND carts.purchased_at >= ?", 3.months.ago)
User.where("NOT EXISTS (#{nq.to_sql})")
更好的是,我会在用户模型中添加一个名为last_purchase_at的列,以提高查询效率

class User
  # add a new column called last_purchase_at
  # index the last_purchase_at column

  def self.dormant_users(period=3.months)
    User.where("last_purchase_at <= ?", period.ago)
  end
end
将此代码添加到迁移脚本中,以设置现有用户模型的“最后一次购买”列

现在,您可以按如下方式获取休眠用户:

User.dormant_users # dormant for last 6 months
User.dormant_users(6.months) # dormant for last 6 months
如果你有一个巨大的购物车,使用MAX和GroupBy可能会很慢。我会使用这种方法

nq = Cart.where("carts.user_id = users.id AND carts.purchased_at >= ?", 3.months.ago)
User.where("NOT EXISTS (#{nq.to_sql})")
更好的是,我会在用户模型中添加一个名为last_purchase_at的列,以提高查询效率

class User
  # add a new column called last_purchase_at
  # index the last_purchase_at column

  def self.dormant_users(period=3.months)
    User.where("last_purchase_at <= ?", period.ago)
  end
end
将此代码添加到迁移脚本中,以设置现有用户模型的“最后一次购买”列

现在,您可以按如下方式获取休眠用户:

User.dormant_users # dormant for last 6 months
User.dormant_users(6.months) # dormant for last 6 months

这只是检索所有在3个月前购买过产品的用户,而不管他们是否在过去3个月内购买过产品。我只想看到在过去3个月内没有购买的用户。这只是检索所有在3个月前购买的用户,不管他们在过去3个月内是否购买。我只想看到在过去3个月内没有购买过产品的用户。active record似乎是一个不错的dsl,但安装此gem以满足这一单一情况可能有点过分。@KJF您可以查看其他查询,也许您会找到更多地方使用squel以避免SQL文本片段。顺便说一句,您不认为您必须使用>签名,而不是在active record周围安装一个很好的dsl,但是安装这个gem来满足这一单一情况可能有点过头了。@KJF您可以看看您的其他查询,也许您会找到更多的地方使用squel来避免SQL文本片段。顺便说一句,你不认为你必须要有>符号,而不是我一直在寻找的。谢谢你能解释一下group方法中User.column_names.map的原因吗?如果我用“users.id”组来代替它,效果也一样。你说得对。在控制台中测试时,我遇到了一些奇怪的问题。但这确实有效。谢谢你的更正!这就是我要找的。谢谢你能解释一下group方法中User.column_names.map的原因吗?如果我用“users.id”组来代替它,效果也一样。你说得对。在控制台中测试时,我遇到了一些奇怪的问题。但这确实有效。谢谢你的更正!