1

関連付けられたカートを持つユーザー モデルがあります。各カートには、 purchase_at datetime 列があります。過去 3 か月間カートを購入していないすべてのユーザーを選択したいと考えています。

私は簡単ですが:

User.joins(:carts).where('not carts.purchased_at < ?', 3.months.ago)

トリックを行いますが、そうではないようです。過去 3 か月間に何かを購入したユーザー レコードが返されます。

何かご意見は?

4

5 に答える 5

5

あなたはこれを行うことができるはずですこれは明白なアクティブレコードにあります:

User.joins(:carts)
  .group("users.id")
  .having("MAX(carts.purchased_at) < ?", 3.months.ago)
于 2012-11-22T17:27:01.110 に答える
1

生の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)

これは単なる提案であることを忘れないでください。(そして、コードにはリファクタリングが必要だと思いますが、アイデアはわかりました。)

于 2012-11-22T16:54:08.097 に答える
1

このような複雑なクエリにはsqueel gem を使用します。

User.where{id.not_in User.joins{carts}.where{carts.purchased_at > 3.months.ago}}
于 2012-11-22T17:02:49.347 に答える
0

巨大なカートを持っている場合、使用するMAXと遅くなる可能性があります。GROUP BY私はこのアプローチを使用します。

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さらに良いことに、モデルに呼び出される列を追加してUser、このクエリを効率的にします。

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

モデルに after_create コールバックを追加して、Cartモデルを更新しUserます。

class Cart
  after_create :update_user_last_purchase_at

  def update_user_last_purchase_at
    user.update_attribute(:last_purchase_at, purchased_at)
  end
end

このコードを移行スクリプトに追加してlast_purchase_at、既存のUserモデルの列を設定します。

User.connection.execute("
  UPDATE users 
  JOIN (
    SELECT a.user_id, MAX(a.purchased_at) purchased_at 
    FROM carts a 
    GROUP BY a.user_id
  ) carts ON carts.user_id= users.id
  SET users.last_purchase_at = cards.purchased_at")

これで、休止中のユーザーを次のように取得できます。

User.dormant_users # dormant for last 6 months
User.dormant_users(6.months) # dormant for last 6 months
于 2012-11-22T19:14:30.927 に答える
0

AR3 (および ARel) を使用している場合:

User.joins(:carts).where(Cart.arel_table[:purchased_at].gt(3.months.ago))
于 2012-11-22T17:09:28.330 に答える