Arel使用ActiveRecord进行子选择?

时间:2011-09-21 19:40:39

标签: mysql ruby-on-rails-3 arel

我正在使用a slightly-modified version of the geocoded gem,当我在我的模型上调用near时调用Deal.near(southwest),其中southwest是一个地理坐标数组):< / p>

SELECT
  deals.*,
  3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) AS distance,
  CAST(DEGREES(ATAN2( RADIANS(addresses.lng - -122.42336332798004), RADIANS(addresses.lat - 37.772476604436974))) + 360 AS decimal) % 360 AS bearing
  FROM "deals"
  INNER JOIN "companies" ON "companies"."id" = "deals"."company_id"
  INNER JOIN "addresses" ON "addresses"."addressable_id" = "companies"."id" AND "addresses"."addressable_type" = 'Company'
  WHERE (
    addresses.lat BETWEEN 37.483013038215276 AND 38.06194017065867
    AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986
  )
  GROUP BY
    deals.id,
    deals.created_at,
    deals.updated_at,
    deals.active,
    deals.company_id,
    deals.title,
    deals.limitations,
    deals.redemption_count,
    addresses.lat,
    addresses.lng
  HAVING 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) <= 20
  ORDER BY 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) ASC

我的问题是,如果Deal的公司有多个Deal es,这将返回多个Address条记录,这是我不想要的。

在MySQL中,我可以省略address.lat, address.lng子句中的GROUP_BY,它会正确地对记录进行分组,但我不能在PostgreSQL中执行此操作。

我知道我可以将上面的整个查询包含在另一个SELECTGROUP_BY中,如下所示:

SELECT
  id, created_at, updated_at, active, title, punches_to_complete, company_id, description, lat, lng, MIN(distance), bearing
  FROM ( ... ) AS t
  GROUP BY company_id

...省略号是上面的查询。那(我相信)应该在MySQL和PostgreSQL中得到我想要的结果。

唯一的问题是我不知道如何在ARel中写这个!

我曾尝试过以下内容,来自AREL大师的la this tip,但我无法让它工作得很好(调用to_sql,因为OP已经说过修复了他的问题逃脱了报价,这让PostgreSQL惹恼了。)

任何人都可以帮我这个???


更新

我已经成功完成了另外一个范围,如下所示:

  scope :nearest, lambda { |coords|
    subquery = "(#{Deal.near(coords).to_sql}) AS t1"
    columns = Deal.columns.map{ |c| c.name }.join(',')
    Deal.select(columns)
      .select('MIN(distance) AS distance')
      .from(subquery)
      .group(columns)
      .order('distance ASC')
  }

但是,这完全打破了可链接性,因为现在我无法调用类似current_user.deals.nearest(coords)的内容,因为它会在子选择之外的其他WHERE deals.user_id = 1上标记。我尝试通过将此逻辑移动到类方法并手动消除SelectManager上的wheres子句来补偿这一点,如下所示:

  def self.nearest(coords)
    subquery = "(#{Deal.near(coords).to_sql}) AS t1"
    columns = Deal.columns.map{ |c| c.name }.join(',')
    query = Deal.select(columns)
      .select('MIN(distance) AS distance')
      .from(subquery)
      .group(columns)
      .order('distance ASC')
    query.arel.ast.cores[0].wheres = []
    query
  end

...但这似乎也不起作用:附加WHERE子句仍然附加:

  

故障/错误:   @ user.deals.nearest(southwest).first.distance.to_f.round(2).should ==        ActiveRecord的:: StatementInvalid:          Mysql2 ::错误:'where'中的未知列'deals.user_id'   子句':SELECT id,created_at,updated_at,user_id,company_id,   MIN(距离)AS距离FROM(SELECT deals。*,3958.755864232 * 2 *   ASIN(SQRT(POWER(SIN)(37.772476604436974 - addresses.lat)* PI()/ 180   / 2),2)+ COS(37.772476604436974 * PI()/ 180)* COS(addresses.lat *   PI()/ 180)* POWER(SIN(( - 122.42336332798004 - addresses.lng)* PI()/   180/2),2)))AS距离,CAST(DEGREES(ATAN2(RADIANS(addresses.lng)    - -122.42336332798004),RADIANS(addresses.lat - 37.772476604436974)))   + 360 AS十进制)%360 AS来自deals INNER JOIN companies   在companiesid = dealscompany_id内部加入addresses开启   addressesaddressable_id = companiesid AND   addressesaddressable_type ='公司'WHERE dealsuser_id =   26 AND(地址范围37.483013038215276和38.06194017065867   AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986)   通过...分组   deals.id,deals.created_at,deals.updated_at,deals.user_id,deals.company_id,   address.lat,addresses.lng拥有3958.755864232 * 2 *   ASIN(SQRT(POWER(SIN)(37.772476604436974 - addresses.lat)* PI()/ 180   / 2),2)+ COS(37.772476604436974 * PI()/ 180)* COS(addresses.lat *   PI()/ 180)* POWER(SIN(( - 122.42336332798004 - addresses.lng)* PI()/   180/2),2)))&lt; = 20订购3958.755864232 * 2 *   ASIN(SQRT(POWER(SIN)(37.772476604436974 - addresses.lat)* PI()/ 180   / 2),2)+ COS(37.772476604436974 * PI()/ 180)* COS(addresses.lat *   PI()/ 180)* POWER(SIN(( - 122.42336332798004 - addresses.lng)* PI()/   180/2),2)))ASC)AS t1 WHERE dealsuser_id = 26 GROUP BY   id,created_at,updated_at,user_id,company_id ORDER BY distance ASC   限制1

我正在尝试用ARel做什么?上面的其他范围对我来说真的很脏(将子查询解析为原始SQL?我认为ARel应该这样做,所以我从来没有这样做过!)

相关问题:ARel能否为CTE(公用表格表达式)制定跨数据库查询?

0 个答案:

没有答案
相关问题