2

スコープ内のオブジェクトを適切にカウントする方法がわかりません。

この例では、製品( "skus")にlatとlngがあり、ユーザーもそうだと仮定します。

動作するfind_by_sqlの例があります。

  def self.with_max_distance(user, distance)
    Sku.find_by_sql(
    <<-eos
      SELECT *,
      ( 3959 * acos( cos( radians(#{user.lat}) ) * cos( radians( skus.lat ) )
      * cos( radians(skus.lng) - radians(#{user.lng})) + sin(radians(#{user.lat}))
      * sin( radians(skus.lat)))) AS distance
      FROM skus
      HAVING distance < #{distance}
    eos
    )
  end

次のスコープを部分的に機能させることができました。

  scope :scope_with_max_distance, lambda { |user, distance|
    { :select => "skus.*, ( 3959 * acos( cos( radians(#{user.lat}) ) * cos( radians( skus.lat ) ) * cos( radians(skus.lng) - radians(#{user.lng})) + sin(radians(#{user.lat})) * sin( radians(skus.lat)))) AS distance",
      :having => "distance < #{distance}"
    }
  }

スコープはオブジェクトを正しく取得しているように見えます。私はそれを広範囲にテストしていませんが、他のスコープとチェーンすると機能するように見えます。

しかし、私はcount()オブジェクトを作成することができず、それは本当に迷惑です。使用できることはわかっていますlength()が、countで機能しないという事実から、これを行うためのより良い方法があるかどうか疑問に思います。

1.9.3p125 :048 > Sku.scope_with_max_distance(User.first, 50).limit(10).count
  User Load (0.5ms)  SELECT `users`.* FROM `users` LIMIT 1
   (0.6ms)  SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM `skus` HAVING distance < 50 LIMIT 10) subquery_for_count 
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'distance' in 'having clause': SELECT COUNT(count_column) FROM (SELECT  1 AS count_column FROM `skus`  HAVING distance < 50 LIMIT 10) subquery_for_count 

アドバイスやアイデアをいただければ幸いです。さまざまなアプローチを試しましたが、完全に機能するアプローチを見つけることができませんでした。問題をさらに明確にする必要がある場合はお知らせください。

4

1 に答える 1

4

countselect可能な限り効率的にカウントを構築するために必要な単純な要素だけに置き換えます。SQLが有効であることを確認するために他の制約をチェックしません。distanceこの問題を回避するために、のエイリアスをhaving選択する数式に置き換えることができます。また、データベースに移植できない暗黙のグループ化を避けるためにhaving、に置き換えることをお勧めします。where

scope :scope_with_max_distance, lambda { |user, distance|
  distance_formula = "(3959 * acos( cos( radians(#{user.lat}) ) * cos( radians( skus.lat ) ) * cos( radians(skus.lng) - radians(#{user.lng})) + sin(radians(#{user.lat})) * sin( radians(skus.lat))))"
  { :select => "skus.*, #{distance_formula} AS distance",
    :where => "#{distance_formula} < #{distance}"
  }
}

最後にもう1つ、あなたが呼んcountlimit(10)いるのは、カウントが10を超えることは決してないということです。それは本質的に間違っているわけではありませんが、それがあなたの意図したことかどうかはわかりません。

于 2012-12-24T21:33:37.360 に答える